home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-07-11 | 321.0 KB | 11,305 lines |
- {$A+,B-,D+,L+,N-,E-,O-,R-,S-,V-,G-,F-,I-,X-}
- {$M 16384,0,655360}
- {$UNDEF IOcheck}
-
- {Programtool for the realization of fast animations on the VGA-graphic- }
- {card by: Kai Rohrbacher, 1988-1993, Turbo-Pascal 6.0 }
-
- { Features: }
-
- { - flickerfree animation by using page-flipping, watching retrace }
- { signals and usage of a special 256 color mode of the VGA }
- { - sprite movement in any pixel-increments you want }
- { - arbitrary background image for the animation }
- { - animations may be restricted to a screen window }
- { - full use of the VGA's 256-color mode }
- { - several sprite display methods available: }
- { - sprites can be declared to be transparent with regard to the background }
- { or other sprites pixel by pixel }
- { - sprites can change their color depending on the underlying background }
- { image (-> shadow function) }
- { - pixel precise hit-detection routine for sprite collisions built in }
- { - correct clipping of sprites at the screen boundaries when moving on- or }
- { offscreen }
- { - up to 32767 different sprites (default: 1000) }
- { - up to 32767 sprites may be simultaneously active (default: 500) }
- { - maximal size of each sprite = 64k }
- { - maximal size of all loaded sprites only restricted by available memory }
- { - works with virtual coordinates in the range -16000..+16000, thus }
- { simple creation of horizontal/vertical "scrolling" applications }
- { - scrolling background image, too }
- { - restricting the animations to a window is possible }
- { - several supporting routines to: draw lines (with built in clipping- }
- { algorithm), points and graphic-text (incl. clipping), automatic heap }
- { management for storing/loading sprites, handling background images, }
- { changing sprite display modes at runtime, adjustment for different }
- { CPU-clocks, ... }
-
- UNIT ANIVGA;
- INTERFACE
-
- USES CRT,DOS,Compression;
-
- CONST ANIVGAVersion=12; {version number}
- NMAX=499;
- XMAX=319;
- YMAX=199;
- LoadMAX=1000; {max. number of simultaneously active sprites }
- LINESIZE=(XMAX+1) DIV 4; {size of one row = 80 bytes }
- PAGESIZE=(YMAX+1)*LINESIZE; {200 rows at 320/4 bytes each}
- BACKGNDPAGE=2;
- SCROLLPAGE=3;
-
- STATIC=0; {constants for background mode}
- SCROLLING=1;
-
- MaxTiles=10000; {max. number of background tiles }
- StartVirtualX:INTEGER=0; {upper left image corner }
- StartVirtualY:INTEGER=0;
-
- {supported display modes for sprites: }
- Display_NORMAL=0; {normal : transparent for color 0 }
- Display_FAST =1; {fast : don't take background into account}
- Display_SHADOW=2; {shadow : color lookup driven by background data}
- Display_SHADOWEXACT=3; {color 0 is transparent for shadows, too }
- Display_UNKNOWN=255;{error value}
-
- {error codes of the animation package: }
- Err_None=0;
- Err_NotEnoughMemory=1;
- Err_FileIO=2;
- Err_InvalidSpriteNumber=3;
- Err_NoSprite=4;
- Err_InvalidPageNumber=5;
- Err_NoVGA=6;
- Err_NoPicture=7;
- Err_InvalidPercentage=8;
- Err_NoTile=9;
- Err_InvalidTileNumber=10;
- Err_InvalidCoordinates=11;
- Err_BackgroundToBig=12;
- Err_InvalidMode=13;
- Err_InvalidSpriteLoadNumber=14;
- Err_NoPalette=15;
- Err_PaletteWontFit=16;
- Err_InvalidFade=17;
- Err_NoFont=18;
- Err_EMSError=19;
-
- CONST MaxFontHeight=16;
- MaxFontWidth=15;
- TagMonoFont=0;
- TagColorFont=1;
- TagProportional=$80;
- TYPE MonoFontChar=ARRAY[0..MaxFontHeight-1] OF WORD;
- MonoFont=ARRAY[0..255] OF MonoFontchar;
- ColorFontChar=ARRAY[0..MaxFontHeight-1] OF ARRAY[0..MaxFontWidth-1] OF BYTE;
- ColorFont=ARRAY[0..255] OF ColorFontchar;
- FontOrient=(horizontal,vertical); {possible text directions }
- CONST GraphTextOrientation:FontOrient=horizontal; {actual output direction }
- GraphTextColor:BYTE=white; {actual text color }
- GraphTextBackground:BYTE=white;
- CurrentFont:POINTER=NIL; {pointer to actual font }
- UpdateOuterArea:BYTE=2; {update outer background area}
- WinClip:BOOLEAN=FALSE; {clip pixel to window? }
- VAR FontHeight,
- FontWidth,
- FontType,
- FontProportion:BYTE;
- FontWidthTable:ARRAY[0..255] OF BYTE;
-
- TYPE Table=ARRAY[0..NMAX] OF INTEGER;
- ColorTable=ARRAY[0..255] OF BYTE;
-
- TYPE PaletteEntry=RECORD red,green,blue:BYTE END;
- Palette=ARRAY[0..255] OF PaletteEntry;
- PalettePtr=^Palette;
-
- CONST DefaultColors:Palette= {default palette colors of 256color mode}
- ( {read out by using the VGA-BIOS-calls: }
- (red: 0; green: 0; blue: 0), { MOV AX,1017h ;read palette registers}
- (red: 0; green: 0; blue: 42), { XOR BX,BX ;start with color 0 }
- (red: 0; green: 42; blue: 0), { MOV CX,100h ;all 256 colors }
- (red: 0; green: 42; blue: 42), { LES DX,Ziel ;to ES:DX }
- (red: 42; green: 0; blue: 0), { INT 10h }
- (red: 42; green: 0; blue: 42), {Attention! These values can/could be }
- (red: 42; green: 21; blue: 0), {read out directly from the VGA card not}
- (red: 42; green: 42; blue: 42), {until a graphic mode has been activated; }
- (red: 21; green: 21; blue: 21), {thus, here they were defined "static"}
- (red: 21; green: 21; blue: 63),
- (red: 21; green: 63; blue: 21),
- (red: 21; green: 63; blue: 63),
- (red: 63; green: 21; blue: 21),
- (red: 63; green: 21; blue: 63),
- (red: 63; green: 63; blue: 21),
- (red: 63; green: 63; blue: 63),
- (red: 0; green: 0; blue: 0),
- (red: 5; green: 5; blue: 5),
- (red: 8; green: 8; blue: 8),
- (red: 11; green: 11; blue: 11),
- (red: 14; green: 14; blue: 14),
- (red: 17; green: 17; blue: 17),
- (red: 20; green: 20; blue: 20),
- (red: 24; green: 24; blue: 24),
- (red: 28; green: 28; blue: 28),
- (red: 32; green: 32; blue: 32),
- (red: 36; green: 36; blue: 36),
- (red: 40; green: 40; blue: 40),
- (red: 45; green: 45; blue: 45),
- (red: 50; green: 50; blue: 50),
- (red: 56; green: 56; blue: 56),
- (red: 63; green: 63; blue: 63),
- (red: 0; green: 0; blue: 63),
- (red: 16; green: 0; blue: 63),
- (red: 31; green: 0; blue: 63),
- (red: 47; green: 0; blue: 63),
- (red: 63; green: 0; blue: 63),
- (red: 63; green: 0; blue: 47),
- (red: 63; green: 0; blue: 31),
- (red: 63; green: 0; blue: 16),
- (red: 63; green: 0; blue: 0),
- (red: 63; green: 16; blue: 0),
- (red: 63; green: 31; blue: 0),
- (red: 63; green: 47; blue: 0),
- (red: 63; green: 63; blue: 0),
- (red: 47; green: 63; blue: 0),
- (red: 31; green: 63; blue: 0),
- (red: 16; green: 63; blue: 0),
- (red: 0; green: 63; blue: 0),
- (red: 0; green: 63; blue: 16),
- (red: 0; green: 63; blue: 31),
- (red: 0; green: 63; blue: 47),
- (red: 0; green: 63; blue: 63),
- (red: 0; green: 47; blue: 63),
- (red: 0; green: 31; blue: 63),
- (red: 0; green: 16; blue: 63),
- (red: 31; green: 31; blue: 63),
- (red: 39; green: 31; blue: 63),
- (red: 47; green: 31; blue: 63),
- (red: 55; green: 31; blue: 63),
- (red: 63; green: 31; blue: 63),
- (red: 63; green: 31; blue: 55),
- (red: 63; green: 31; blue: 47),
- (red: 63; green: 31; blue: 39),
- (red: 63; green: 31; blue: 31),
- (red: 63; green: 39; blue: 31),
- (red: 63; green: 47; blue: 31),
- (red: 63; green: 55; blue: 31),
- (red: 63; green: 63; blue: 31),
- (red: 55; green: 63; blue: 31),
- (red: 47; green: 63; blue: 31),
- (red: 39; green: 63; blue: 31),
- (red: 31; green: 63; blue: 31),
- (red: 31; green: 63; blue: 39),
- (red: 31; green: 63; blue: 47),
- (red: 31; green: 63; blue: 55),
- (red: 31; green: 63; blue: 63),
- (red: 31; green: 55; blue: 63),
- (red: 31; green: 47; blue: 63),
- (red: 31; green: 39; blue: 63),
- (red: 45; green: 45; blue: 63),
- (red: 49; green: 45; blue: 63),
- (red: 54; green: 45; blue: 63),
- (red: 58; green: 45; blue: 63),
- (red: 63; green: 45; blue: 63),
- (red: 63; green: 45; blue: 58),
- (red: 63; green: 45; blue: 54),
- (red: 63; green: 45; blue: 49),
- (red: 63; green: 45; blue: 45),
- (red: 63; green: 49; blue: 45),
- (red: 63; green: 54; blue: 45),
- (red: 63; green: 58; blue: 45),
- (red: 63; green: 63; blue: 45),
- (red: 58; green: 63; blue: 45),
- (red: 54; green: 63; blue: 45),
- (red: 49; green: 63; blue: 45),
- (red: 45; green: 63; blue: 45),
- (red: 45; green: 63; blue: 49),
- (red: 45; green: 63; blue: 54),
- (red: 45; green: 63; blue: 58),
- (red: 45; green: 63; blue: 63),
- (red: 45; green: 58; blue: 63),
- (red: 45; green: 54; blue: 63),
- (red: 45; green: 49; blue: 63),
- (red: 0; green: 0; blue: 28),
- (red: 7; green: 0; blue: 28),
- (red: 14; green: 0; blue: 28),
- (red: 21; green: 0; blue: 28),
- (red: 28; green: 0; blue: 28),
- (red: 28; green: 0; blue: 21),
- (red: 28; green: 0; blue: 14),
- (red: 28; green: 0; blue: 7),
- (red: 28; green: 0; blue: 0),
- (red: 28; green: 7; blue: 0),
- (red: 28; green: 14; blue: 0),
- (red: 28; green: 21; blue: 0),
- (red: 28; green: 28; blue: 0),
- (red: 21; green: 28; blue: 0),
- (red: 14; green: 28; blue: 0),
- (red: 7; green: 28; blue: 0),
- (red: 0; green: 28; blue: 0),
- (red: 0; green: 28; blue: 7),
- (red: 0; green: 28; blue: 14),
- (red: 0; green: 28; blue: 21),
- (red: 0; green: 28; blue: 28),
- (red: 0; green: 21; blue: 28),
- (red: 0; green: 14; blue: 28),
- (red: 0; green: 7; blue: 28),
- (red: 14; green: 14; blue: 28),
- (red: 17; green: 14; blue: 28),
- (red: 21; green: 14; blue: 28),
- (red: 24; green: 14; blue: 28),
- (red: 28; green: 14; blue: 28),
- (red: 28; green: 14; blue: 24),
- (red: 28; green: 14; blue: 21),
- (red: 28; green: 14; blue: 17),
- (red: 28; green: 14; blue: 14),
- (red: 28; green: 17; blue: 14),
- (red: 28; green: 21; blue: 14),
- (red: 28; green: 24; blue: 14),
- (red: 28; green: 28; blue: 14),
- (red: 24; green: 28; blue: 14),
- (red: 21; green: 28; blue: 14),
- (red: 17; green: 28; blue: 14),
- (red: 14; green: 28; blue: 14),
- (red: 14; green: 28; blue: 17),
- (red: 14; green: 28; blue: 21),
- (red: 14; green: 28; blue: 24),
- (red: 14; green: 28; blue: 28),
- (red: 14; green: 24; blue: 28),
- (red: 14; green: 21; blue: 28),
- (red: 14; green: 17; blue: 28),
- (red: 20; green: 20; blue: 28),
- (red: 22; green: 20; blue: 28),
- (red: 24; green: 20; blue: 28),
- (red: 26; green: 20; blue: 28),
- (red: 28; green: 20; blue: 28),
- (red: 28; green: 20; blue: 26),
- (red: 28; green: 20; blue: 24),
- (red: 28; green: 20; blue: 22),
- (red: 28; green: 20; blue: 20),
- (red: 28; green: 22; blue: 20),
- (red: 28; green: 24; blue: 20),
- (red: 28; green: 26; blue: 20),
- (red: 28; green: 28; blue: 20),
- (red: 26; green: 28; blue: 20),
- (red: 24; green: 28; blue: 20),
- (red: 22; green: 28; blue: 20),
- (red: 20; green: 28; blue: 20),
- (red: 20; green: 28; blue: 22),
- (red: 20; green: 28; blue: 24),
- (red: 20; green: 28; blue: 26),
- (red: 20; green: 28; blue: 28),
- (red: 20; green: 26; blue: 28),
- (red: 20; green: 24; blue: 28),
- (red: 20; green: 22; blue: 28),
- (red: 0; green: 0; blue: 16),
- (red: 4; green: 0; blue: 16),
- (red: 8; green: 0; blue: 16),
- (red: 12; green: 0; blue: 16),
- (red: 16; green: 0; blue: 16),
- (red: 16; green: 0; blue: 12),
- (red: 16; green: 0; blue: 8),
- (red: 16; green: 0; blue: 4),
- (red: 16; green: 0; blue: 0),
- (red: 16; green: 4; blue: 0),
- (red: 16; green: 8; blue: 0),
- (red: 16; green: 12; blue: 0),
- (red: 16; green: 16; blue: 0),
- (red: 12; green: 16; blue: 0),
- (red: 8; green: 16; blue: 0),
- (red: 4; green: 16; blue: 0),
- (red: 0; green: 16; blue: 0),
- (red: 0; green: 16; blue: 4),
- (red: 0; green: 16; blue: 8),
- (red: 0; green: 16; blue: 12),
- (red: 0; green: 16; blue: 16),
- (red: 0; green: 12; blue: 16),
- (red: 0; green: 8; blue: 16),
- (red: 0; green: 4; blue: 16),
- (red: 8; green: 8; blue: 16),
- (red: 10; green: 8; blue: 16),
- (red: 12; green: 8; blue: 16),
- (red: 14; green: 8; blue: 16),
- (red: 16; green: 8; blue: 16),
- (red: 16; green: 8; blue: 14),
- (red: 16; green: 8; blue: 12),
- (red: 16; green: 8; blue: 10),
- (red: 16; green: 8; blue: 8),
- (red: 16; green: 10; blue: 8),
- (red: 16; green: 12; blue: 8),
- (red: 16; green: 14; blue: 8),
- (red: 16; green: 16; blue: 8),
- (red: 14; green: 16; blue: 8),
- (red: 12; green: 16; blue: 8),
- (red: 10; green: 16; blue: 8),
- (red: 8; green: 16; blue: 8),
- (red: 8; green: 16; blue: 10),
- (red: 8; green: 16; blue: 12),
- (red: 8; green: 16; blue: 14),
- (red: 8; green: 16; blue: 16),
- (red: 8; green: 14; blue: 16),
- (red: 8; green: 12; blue: 16),
- (red: 8; green: 10; blue: 16),
- (red: 11; green: 11; blue: 16),
- (red: 12; green: 11; blue: 16),
- (red: 13; green: 11; blue: 16),
- (red: 15; green: 11; blue: 16),
- (red: 16; green: 11; blue: 16),
- (red: 16; green: 11; blue: 15),
- (red: 16; green: 11; blue: 13),
- (red: 16; green: 11; blue: 12),
- (red: 16; green: 11; blue: 11),
- (red: 16; green: 12; blue: 11),
- (red: 16; green: 13; blue: 11),
- (red: 16; green: 15; blue: 11),
- (red: 16; green: 16; blue: 11),
- (red: 15; green: 16; blue: 11),
- (red: 13; green: 16; blue: 11),
- (red: 12; green: 16; blue: 11),
- (red: 11; green: 16; blue: 11),
- (red: 11; green: 16; blue: 12),
- (red: 11; green: 16; blue: 13),
- (red: 11; green: 16; blue: 15),
- (red: 11; green: 16; blue: 16),
- (red: 11; green: 15; blue: 16),
- (red: 11; green: 13; blue: 16),
- (red: 11; green: 12; blue: 16),
- (red: 0; green: 0; blue: 0),
- (red: 0; green: 0; blue: 0),
- (red: 0; green: 0; blue: 0),
- (red: 0; green: 0; blue: 0),
- (red: 0; green: 0; blue: 0),
- (red: 0; green: 0; blue: 0),
- (red: 0; green: 0; blue: 0),
- (red: 0; green: 0; blue: 0)
- );
-
- VAR Error:BYTE; {global error variable }
- SpriteN:Table;
- SpriteX:Table;
- SpriteY:Table;
- NextSprite:ARRAY[0..LoadMAX] OF WORD;
- PAGE,PAGEADR,SCROLLADR,BACKGNDADR:WORD;
- Color:BYTE; {drawing color for lines}
- ActualColors:Palette; {actual color palette}
- was_cut:BOOLEAN; {TRUE/FALSE, if "GetImage" had to clip image }
- left_cut, {variables set by "GetImage"; if "was_cut" has}
- right_cut, {been set to TRUE, they will report, where and }
- top_cut, {how much of the image had to been clipped }
- bottom_cut:WORD; {away }
-
- WinXMIN,WinYMIN,WinXMAX,WinYMAX,WinWidth,WinHeight:WORD;
-
- BackgroundMode:BYTE;
- BackTile:ARRAY[0..MaxTiles] OF BYTE; {tile memory }
- XTiles,YTiles:INTEGER; {width, height of defined area }
- BackX1,BackY1,BackX2,BackY2:INTEGER; {coordinates of the defined area }
-
- CONST Fade_Squares =0;
- Fade_Moiree1 =1;
- Fade_Moiree2 =2;
- Fade_Moiree3 =3;
- Fade_Moiree4 =4;
- Fade_Moiree5 =5;
- Fade_Moiree6 =6;
- Fade_Moiree7 =7;
- Fade_Moiree8 =8;
- Fade_Moiree9 =9;
- Fade_Moiree10=10;
- Fade_Moiree11=11;
- Fade_Moiree12=12;
- Fade_Moiree13=13;
- Fade_Moiree14=14;
- Fade_SweepInFromTop=15;
- Fade_SweepInFromBottom=16;
- Fade_SweepInFromLeft=17;
- Fade_SweepInFromRight=18;
- Fade_ScrollInFromTop=19;
- Fade_ScrollInFromBottom=20;
- Fade_ScrollInFromLeft=21;
- Fade_ScrollInFromRight=22;
- Fade_Circles =23;
- Fade_Moiree15=24;
-
- {---- for EMS-routines ----}
-
- CONST BACKTAB:ARRAY[0..3] OF WORD=(0,PAGESIZE,2*PAGESIZE,3*PAGESIZE);
- TYPE Puffer=ARRAY[0..4*PAGESIZE-1 +15] OF BYTE; {buffer for a page }
- VAR buf:^Puffer; {pointer to it}
-
- Const EMSInt = $67; {interrupt used for EMS }
- USEEMS = TRUE; {if FALSE: no usage of existing EMS, }
- {if TRUE : use EMS, if it exists }
-
- Var EMSError:BYTE; {<>0 means: there was an error }
- BackgroundEMSHandle:WORD; {access handle for allocated EMS-block }
- EMSused:BOOLEAN; {tells, whether EMS is really used or not }
-
- PROCEDURE ShadowTab;
- PROCEDURE SetShadowTab(brightness:BYTE);
- PROCEDURE SetPalette(pal:Palette; update:BOOLEAN);
- PROCEDURE GetPalette(VAR pal:Palette);
- PROCEDURE FadeToPalette(destPal:Palette; AnzSteps:WORD);
- FUNCTION LoadPalette(name:String; number:BYTE; VAR pal:Palette):WORD;
- PROCEDURE EnsureEMSConsistency(EMSHandle:WORD);
- PROCEDURE SetCycleTime(milliseconds:WORD);
- PROCEDURE SetSpriteCycle(nr,len:WORD);
- FUNCTION GetImage(x1,y1,x2,y2:INTEGER; pa:WORD):POINTER;
- PROCEDURE PutImage(x,y:INTEGER; p:POINTER; pa:WORD);
- PROCEDURE FreeImageMem(p:POINTER);
- PROCEDURE InitGraph;
- PROCEDURE Screen(pa:WORD);
- PROCEDURE Line(x1,y1,x2,y2:INTEGER; pa:WORD);
- PROCEDURE BackgroundLine(x1,y1,x2,y2:INTEGER);
- FUNCTION GetPixel(x,y:INTEGER):BYTE;
- FUNCTION BackgroundGetPixel(x,y:INTEGER):BYTE;
- FUNCTION PageGetPixel(x,y:INTEGER; pa:WORD):BYTE;
- PROCEDURE PutPixel(x,y:INTEGER; color:Byte);
- PROCEDURE BackgroundPutPixel(x,y:INTEGER; color:Byte);
- PROCEDURE PagePutPixel(x,y:INTEGER; color:BYTE; pa:WORD);
- PROCEDURE LoadFont(s:STRING);
- FUNCTION OutTextLength(s:STRING):WORD;
- PROCEDURE OutTextXY(x,y:INTEGER; pa:WORD; s:STRING);
- PROCEDURE BackgroundOutTextXY(x,y:INTEGER; s:STRING);
- PROCEDURE MakeTextSprite(s:STRING; nr:WORD);
- FUNCTION Hitdetect(s1,s2:INTEGER):BOOLEAN;
- PROCEDURE SetSplitIndex(number:INTEGER);
- FUNCTION GetSplitIndex:INTEGER;
- PROCEDURE SetAnimateWindow(x1,y1,x2,y2:INTEGER);
- PROCEDURE Animate;
- PROCEDURE FreeSpriteMem(number:WORD);
- FUNCTION LoadSprite(name:String; number:WORD):WORD;
- FUNCTION LoadTile(name:STRING; number:BYTE):WORD;
- PROCEDURE SetBackgroundScrollRange(x1,y1,x2,y2:INTEGER);
- PROCEDURE SetBackgroundMode(mode:BYTE);
- PROCEDURE MakeTileArea(FirstTile:BYTE; TileWidth,TileHeight:INTEGER);
- PROCEDURE PutTile(x,y:INTEGER; TileNr:BYTE);
- FUNCTION GetTile(x,y:INTEGER):BYTE;
- PROCEDURE SetOffscreenTile(TileNr:BYTE);
- PROCEDURE SetModeByte(Sp:WORD; M:BYTE);
- FUNCTION GetModeByte(Sp:WORD):BYTE;
- PROCEDURE FillPage(pa:WORD; color:Byte);
- PROCEDURE FillBackground(color:BYTE);
- PROCEDURE GetBackgroundFromPage(pa:WORD);
- PROCEDURE WritePage(name:STRING; pa:WORD);
- PROCEDURE LoadPage(name:STRING; pa:WORD);
- PROCEDURE WriteBackgroundPage(name:STRING);
- PROCEDURE LoadBackgroundPage(name:STRING);
- PROCEDURE FadeIn(pa,ti,style:WORD);
- PROCEDURE CopyVRAMtoVRAM(source,dest:POINTER; len:WORD);
- PROCEDURE IntroScroll(n,wait:WORD);
- PROCEDURE InitRoutines;
- PROCEDURE CloseRoutines;
- FUNCTION GetErrorMessage:STRING;
- FUNCTION FindFile(P:PathStr):PathStr;
-
- {--------------------------------------------------------------------------}
-
- IMPLEMENTATION
-
- CONST ANIVGAVersionS:STRING[11]='AniVGA V1.2'; {version number}
- StartIndex=0;
- EndIndex=StartIndex+3;
- {offset addresses of the graphic pages (in segment $A000):}
- Offset_Adr:Array[StartIndex..EndIndex] OF WORD=($0000,$3E80,$7D00,$BB80);
- {segment addresses of graphic pages (with offset = 0):}
- Segment_Adr:ARRAY[StartIndex..EndIndex] OF WORD=($A000,$A3E8,$A7D0,$ABB8);
-
- {sprite header format: }
-
- {0..1 DW offset_ptr_to_plane0_data}
- {2..3 DW offset_ptr_to_plane1_data}
- {4..5 DW offset_ptr_to_plane2_data}
- {6..7 DW offset_ptr_to_plane3_data}
- {8..9 DW width (in groups of 4) (in German: "Breite")}
- {10..11 DW heigth in rows (in German: "Höhe")}
- {12..15 DB 1,2,4,8 ; translate-table used for port-accesses}
- {16..17 DW SpriteLength ; length of this sprite in bytes}
- { ; now follows the scratch area reserved for temporary}
- { ; variables: ("a|b" = used for a and b)}
- {18..19 DW ? ; licutoff_ | hit1xfirst}
- {20..21 DW ? ; zeilenadr | hit1yfirst}
- {22..23 DW ? ; bildx | hit2xfirst}
- {24..25 DW ? ; yoffset_ | hit2yfirst}
- {26..27 DW ? ; end_min_start | ueberlappx_1}
- {28..29 DW ? ; WinXMIN_ | ueberlappy_1}
- {30..31 DW ? ; WinXMAX_ | x1}
- {32..33 DW ? ; WinYMIN_ | x2}
- {34..35 DW ? ; | y1}
- {36..37 DW ? ; | y2}
- {38..39 DB 'K','R' ; tag used for sprites}
- {40 DB 1 ; version number}
- {41 DB 0 ; display mode used for sprite}
- {42..43 DW offset_ptr_to_left_boundary_data }
- {44..45 DW offset_ptr_to_right_boundary_data}
- {46..47 DW offset_ptr_to_top_boundary_data }
- {48..49 DW offset_ptr_to_bottom_boundary_data}
- {50..?? DB data }
-
- {for ex.: xxrxxxxx, with: r=red=40, g=green=45, b=blue=35, x=white=30}
- { xrgrxxxx}
- { rbgbrxxx}
-
- {addresses of important values inside the sprite header: }
- Left=42;
- Right=44;
- Top=46;
- Bottom=48;
- Breite=8;
- Hoehe=10;
- Translate=12;
- SpriteLength=16;
- Kennung=38;
- Version=40;
- Modus=41;
-
- {addresses of temporary variables for the drawing routines:}
- licutoff_=18;
- zeilenadr=20;
- bildx=22;
- yoffset_=24;
- end_min_start=26;
- WinXMIN_=28;
- WinXMAX_=30;
- WinYMIN_=32;
-
- {addresses of temporary variables for the collision detection routine:}
- hit1xfirst=18;
- hit1yfirst=20;
- hit2xfirst=22;
- hit2yfirst=24;
- ueberlappx_1=26;
- ueberlappy_1=28;
- x1=30;
- x2=32;
- y1=34;
- y2=36;
-
- TranslateTab:ARRAY[0..3] OF BYTE=(1,2,4,8); {For mask addressing }
- PICHeader:STRING[3]='PIC'; {tag in picture files }
- Schatten :BYTE=70; {default brightness of shadows }
-
- TYPE SpriteHeader= RECORD
- Zeiger_auf_Plane:Array[0..3] OF Word;
- Breite_in_4er_Gruppen:WORD;
- Hoehe_in_Zeilen:WORD;
- Translate:Array[1..4] OF Byte;
- SpriteLength:WORD;
- Dummy:Array[1..10] OF Word;
- Kennung:ARRAY[1..2] OF CHAR;
- Version:BYTE;
- Modus:BYTE;
- ZeigerL,ZeigerR,ZeigerO,ZeigerU:Word;
- END;
-
- CONST Kopf=SizeOf(SpriteHeader);
- FontMask:ARRAY[0..MaxFontWidth-1] OF WORD=
- ($4000,$2000,$1000,$800,$400,$200,$100,$80,$40,$20,$10,8,4,2,1);
- internalFont:ARRAY[0..255,0..5] OF BYTE= {used font: }
- (( 0, 0, 0, 0, 0, 0), {#0} {selfmade 6x6 font (ugly..)}
- ( 0, 54, 0, 62, 28, 0), {#1}
- ( 62, 42, 62, 34, 54, 62), {#2}
- ( 0, 20, 62, 62, 28, 8), {#3}
- ( 0, 8, 28, 62, 28, 8), {#4}
- ( 8, 28, 54, 62, 8, 28), {#5}
- ( 8, 28, 62, 62, 8, 28), {#6}
- ( 0, 8, 54, 54, 8, 0), {#7}
- ( 62, 54, 42, 42, 54, 62), {#8}
- ( 0, 28, 50, 38, 28, 0), {#9}
- ( 62, 34, 42, 42, 34, 62), {#10}
- ( 14, 6, 8, 28, 34, 28), {#11}
- ( 28, 34, 28, 8, 62, 8), {#12}
- ( 14, 10, 8, 8, 56, 56), {#13}
- ( 0, 30, 18, 30, 18, 54), {#14}
- ( 0, 8, 42, 20, 42, 8), {#15}
- ( 0, 32, 56, 62, 56, 32), {#16}
- ( 0, 2, 14, 62, 14, 2), {#17}
- ( 8, 28, 42, 42, 28, 8), {#18}
- ( 0, 54, 54, 54, 0, 54), {#19}
- ( 0, 30, 42, 26, 10, 10), {#20}
- ( 6, 8, 4, 10, 36, 24), {#21}
- ( 0, 0, 0, 0, 62, 62), {#22}
- ( 8, 28, 8, 28, 8, 62), {#23}
- ( 0, 8, 28, 62, 8, 8), {#24}
- ( 0, 8, 8, 62, 28, 8), {#25}
- ( 0, 8, 4, 62, 4, 8), {#26}
- ( 0, 8, 16, 62, 16, 8), {#27}
- ( 0, 0, 48, 62, 0, 0), {#28}
- ( 0, 0, 20, 62, 20, 0), {#29}
- ( 0, 0, 0, 8, 28, 62), {#30}
- ( 0, 0, 62, 28, 8, 0), {#31}
- ( 0, 0, 0, 0, 0, 0), { }
- ( 0, 12, 12, 12, 0, 12), {!}
- ( 0, 20, 20, 0, 0, 0), {"}
- ( 0, 20, 62, 20, 62, 20), {#}
- ( 8, 30, 40, 28, 10, 60), { $}
- ( 0, 50, 4, 8, 16, 38), {%}
- ( 0, 28, 54, 28, 38, 26), {&}
- ( 0, 4, 8, 0, 0, 0), {'}
- ( 0, 28, 48, 48, 48, 28), {(}
- ( 0, 56, 12, 12, 12, 56), {)}
- ( 0, 20, 8, 62, 8, 20), {*}
- ( 0, 0, 8, 62, 8, 0), {+}
- ( 0, 0, 0, 8, 8, 16), {,}
- ( 0, 0, 0, 62, 0, 0), {-}
- ( 0, 0, 0, 0, 12, 0), {.}
- ( 1, 2, 4, 8, 16, 32), {/}
- ( 0, 28, 38, 42, 50, 28), {0}
- ( 0, 12, 28, 12, 12, 30), {1}
- ( 0, 60, 6, 28, 48, 62), {2}
- ( 0, 60, 6, 28, 6, 60), {3}
- ( 0, 48, 52, 62, 12, 12), {4}
- ( 0, 62, 48, 60, 6, 60), {5}
- ( 0, 62, 32, 62, 34, 62), {6}
- ( 0, 62, 6, 12, 24, 24), {7}
- ( 0, 28, 54, 28, 54, 28), {8}
- ( 0, 28, 34, 30, 2, 28), {9}
- ( 0, 0, 8, 0, 8, 0), {:}
- ( 0, 0, 8, 0, 8, 16), {;}
- ( 0, 6, 12, 24, 12, 6), {<}
- ( 0, 0, 62, 0, 62, 0), {=}
- ( 0, 24, 12, 6, 12, 24), {>}
- ( 28, 34, 4, 8, 0, 8), {?}
- ( 0, 28, 34, 46, 32, 30), {@}
- ( 0, 28, 50, 62, 50, 50), {A}
- ( 0, 60, 50, 60, 50, 60), {B}
- ( 0, 30, 48, 48, 48, 30), {C}
- ( 0, 60, 54, 50, 54, 60), {D}
- ( 0, 62, 48, 60, 48, 62), {E}
- ( 0, 62, 48, 60, 48, 48), {F}
- ( 0, 30, 48, 54, 50, 30), {G}
- ( 0, 50, 50, 62, 50, 50), {H}
- ( 0, 30, 12, 12, 12, 30), {I}
- ( 0, 62, 2, 2, 50, 28), {J}
- ( 0, 50, 52, 56, 52, 50), {K}
- ( 0, 48, 48, 48, 48, 62), {L}
- ( 0, 34, 54, 42, 34, 34), {M}
- ( 0, 34, 50, 42, 38, 34), {N}
- ( 0, 28, 50, 50, 50, 28), {O}
- ( 0, 60, 50, 60, 48, 48), {P}
- ( 0, 24, 52, 52, 52, 26), {Q}
- ( 0, 60, 34, 60, 52, 50), {R}
- ( 0, 62, 48, 62, 6, 62), {S}
- ( 0, 62, 24, 24, 24, 24), {T}
- ( 0, 50, 50, 50, 50, 62), {U}
- ( 0, 50, 50, 50, 50, 12), {V}
- ( 0, 34, 34, 42, 62, 20), {W}
- ( 0, 34, 54, 28, 54, 34), {X}
- ( 0, 50, 50, 28, 12, 12), {Y}
- ( 0, 62, 6, 28, 48, 62), {Z}
- ( 0, 30, 24, 24, 24, 30), {[}
- ( 32, 16, 8, 4, 2, 1), {\}
- ( 0, 30, 6, 6, 6, 30), {]}
- ( 8, 20, 34, 0, 0, 0), {^}
- ( 0, 0, 0, 0, 0, 62), {_}
- ( 16, 8, 0, 0, 0, 0), {`}
- ( 0, 0, 28, 50, 50, 30), {a}
- ( 0, 32, 60, 34, 34, 60), {b}
- ( 0, 0, 30, 48, 48, 30), {c}
- ( 0, 2, 30, 34, 34, 30), {d}
- ( 0, 0, 28, 62, 32, 28), {e}
- ( 0, 6, 8, 30, 8, 8), {f}
- ( 0, 28, 34, 30, 2, 28), {g}
- ( 0, 48, 60, 50, 50, 50), {h}
- ( 12, 0, 12, 12, 12, 12), {i}
- ( 6, 0, 6, 6, 54, 28), {j}
- ( 0, 48, 52, 56, 54, 54), {k}
- ( 0, 24, 24, 24, 24, 14), {l}
- ( 0, 0, 52, 62, 42, 34), {m}
- ( 0, 0, 60, 50, 50, 50), {n}
- ( 0, 0, 28, 50, 50, 28), {o}
- ( 0, 0, 60, 50, 60, 48), {p}
- ( 0, 0, 28, 38, 30, 6), {q}
- ( 0, 0, 44, 26, 24, 24), {r}
- ( 0, 14, 16, 12, 34, 28), {s}
- ( 0, 24, 62, 24, 26, 12), {t}
- ( 0, 0, 50, 50, 50, 30), {u}
- ( 0, 0, 50, 50, 50, 28), {v}
- ( 0, 0, 34, 42, 42, 28), {w}
- ( 0, 0, 54, 24, 12, 54), {x}
- ( 0, 0, 50, 62, 2, 28), {y}
- ( 0, 0, 60, 12, 48, 62), {z}
- ( 0, 14, 24, 48, 24, 14),(*{*)
- ( 0, 4, 4, 0, 4, 4), {|}
- ( 0, 56, 12, 6, 12, 56),(*}*)
- ( 0, 26, 36, 0, 0, 0), {~}
- ( 0, 8, 20, 34, 62, 0), {#127}
- ( 28, 50, 32, 50, 28, 48), {#128}
- ( 0, 50, 0, 50, 50, 30), {#129}
- ( 6, 8, 28, 62, 32, 28), {#130}
- ( 4, 10, 0, 30, 49, 31), {#131}
- ( 26, 0, 28, 50, 50, 30), {#132}
- ( 12, 2, 28, 34, 34, 30), {#133}
- ( 4, 10, 4, 28, 50, 30), {#134}
- ( 0, 30, 48, 30, 4, 24), {#135}
- ( 28, 0, 28, 62, 48, 28), {#136}
- ( 20, 0, 28, 62, 32, 28), {#137}
- ( 12, 2, 28, 62, 48, 28), {#138}
- ( 26, 0, 12, 12, 12, 12), {#139}
- ( 12, 18, 0, 12, 12, 12), {#140}
- ( 24, 4, 0, 12, 12, 12), {#141}
- ( 50, 0, 28, 50, 62, 50), {#142}
- ( 12, 0, 28, 50, 62, 50), {#143}
- ( 28, 62, 48, 60, 48, 62), {#144}
- ( 0, 52, 10, 28, 40, 22), {#145}
- ( 0, 14, 20, 62, 36, 38), {#146}
- ( 8, 20, 0, 28, 50, 28), {#147}
- ( 20, 0, 28, 50, 50, 28), {#148}
- ( 24, 4, 0, 28, 50, 28), {#149}
- ( 8, 20, 0, 50, 50, 30), {#150}
- ( 24, 4, 0, 50, 50, 30), {#151}
- ( 20, 0, 50, 62, 2, 28), {#152}
- ( 20, 0, 28, 50, 50, 28), {#153}
- ( 50, 0, 50, 50, 50, 62), {#154}
- ( 4, 30, 32, 32, 30, 4), {#155}
- ( 12, 18, 56, 16, 34, 62), {#156}
- ( 54, 8, 62, 8, 62, 8), {#157}
- ( 48, 40, 52, 46, 36, 38), {#158}
- ( 12, 10, 24, 12, 40, 24), {#159}
- ( 12, 16, 0, 28, 34, 30), {#160}
- ( 12, 16, 0, 8, 8, 8), {#161}
- ( 12, 16, 0, 28, 50, 28), {#162}
- ( 12, 16, 0, 50, 50, 30), {#163}
- ( 26, 36, 0, 44, 18, 18), {#164}
- ( 26, 36, 0, 50, 42, 38), {#165}
- ( 28, 36, 26, 0, 62, 0), {#166}
- ( 28, 34, 28, 0, 62, 0), {#167}
- ( 8, 0, 8, 16, 34, 28), {#168}
- ( 0, 0, 63, 48, 0, 0), {#169}
- ( 0, 0, 63, 3, 0, 0), {#170}
- ( 18, 20, 8, 16, 42, 10), {#171}
- ( 18, 20, 8, 20, 38, 2), {#172}
- ( 12, 0, 12, 12, 12, 0), {#173}
- ( 10, 20, 40, 20, 10, 0), {#174}
- ( 40, 20, 10, 20, 40, 0), {#175}
- ( 21, 42, 21, 42, 21, 42), {#176}
- ( 63, 63, 63, 63, 63, 63), {#177}
- ( 42, 21, 42, 21, 42, 21), {#178}
- ( 4, 4, 4, 4, 4, 4), {#179}
- ( 4, 4, 4, 60, 4, 4), {#180}
- ( 4, 4, 60, 4, 60, 4), {#181}
- ( 10, 10, 10, 58, 10, 10), {#182}
- ( 0, 0, 0, 62, 10, 10), {#183}
- ( 0, 0, 60, 4, 60, 4), {#184}
- ( 10, 10, 58, 2, 58, 10), {#185}
- ( 10, 10, 10, 10, 10, 10), {#186}
- ( 0, 0, 62, 2, 58, 10), {#187}
- ( 10, 10, 58, 2, 62, 0), {#188}
- ( 10, 10, 10, 62, 0, 0), {#189}
- ( 4, 4, 60, 4, 60, 0), {#190}
- ( 0, 0, 0, 60, 4, 4), {#191}
- ( 4, 4, 4, 7, 0, 0), {#192}
- ( 4, 4, 4, 63, 0, 0), {#193}
- ( 0, 0, 0, 63, 4, 4), {#194}
- ( 4, 4, 4, 7, 4, 4), {#195}
- ( 0, 0, 0, 63, 0, 0), {#196}
- ( 4, 4, 4, 63, 4, 4), {#197}
- ( 4, 4, 7, 4, 7, 4), {#198}
- ( 10, 10, 10, 11, 10, 10), {#199}
- ( 10, 10, 11, 8, 15, 0), {#200}
- ( 0, 0, 15, 8, 11, 10), {#201}
- ( 10, 10, 59, 0, 63, 0), {#202}
- ( 0, 0, 63, 0, 59, 10), {#203}
- ( 10, 10, 11, 8, 11, 10), {#204}
- ( 0, 0, 63, 0, 63, 0), {#205}
- ( 10, 10, 59, 0, 59, 10), {#206}
- ( 4, 4, 63, 0, 63, 0), {#207}
- ( 10, 10, 10, 63, 0, 0), {#208}
- ( 0, 0, 63, 0, 63, 4), {#209}
- ( 0, 0, 0, 63, 10, 10), {#210}
- ( 10, 10, 10, 15, 0, 0), {#211}
- ( 4, 4, 7, 4, 7, 0), {#212}
- ( 0, 0, 7, 4, 7, 4), {#213}
- ( 0, 0, 0, 15, 10, 10), {#214}
- ( 10, 10, 10, 63, 10, 10), {#215}
- ( 4, 4, 63, 4, 63, 4), {#216}
- ( 4, 4, 4, 60, 0, 0), {#217}
- ( 0, 0, 7, 4, 4, 4), {#218}
- ( 63, 63, 63, 63, 63, 63), {#219}
- ( 0, 0, 0, 63, 63, 63), {#220}
- ( 48, 48, 48, 48, 48, 48), {#221}
- ( 3, 3, 3, 3, 3, 3), {#222}
- ( 63, 63, 63, 0, 0, 0), {#223}
- ( 0, 0, 26, 36, 36, 26), {#224}
- ( 0, 28, 38, 44, 34, 44), {#225}
- ( 0, 62, 34, 32, 32, 32), {#226}
- ( 0, 0, 62, 20, 20, 20), {#227}
- ( 62, 18, 8, 16, 34, 62), {#228}
- ( 0, 0, 30, 36, 36, 24), {#229}
- ( 0, 18, 18, 30, 16, 48), {#230}
- ( 0, 0, 26, 44, 8, 8), {#231}
- ( 0, 62, 8, 20, 8, 62), {#232}
- ( 0, 28, 34, 62, 34, 28), {#233}
- ( 0, 28, 34, 34, 20, 54), {#234}
- ( 14, 16, 8, 28, 34, 28), {#235}
- ( 0, 0, 20, 42, 20, 0), {#236}
- ( 0, 2, 20, 42, 20, 32), {#237}
- ( 0, 30, 32, 62, 32, 30), {#238}
- ( 0, 0, 28, 34, 34, 34), {#239}
- ( 0, 62, 0, 62, 0, 62), {#240}
- ( 0, 8, 28, 8, 0, 62), {#241}
- ( 16, 8, 4, 8, 16, 62), {#242}
- ( 4, 8, 16, 8, 4, 62), {#243}
- ( 4, 10, 8, 8, 8, 8), {#244}
- ( 8, 8, 8, 8, 40, 16), {#245}
- ( 0, 8, 0, 62, 0, 8), {#246}
- ( 26, 36, 0, 26, 36, 0), {#247}
- ( 24, 36, 24, 0, 0, 0), {#248}
- ( 0, 0, 0, 12, 0, 0), {#249}
- ( 0, 0, 0, 4, 0, 0), {#250}
- ( 15, 8, 8, 40, 24, 8), {#251}
- ( 44, 18, 18, 0, 0, 0), {#252}
- ( 56, 4, 24, 32, 60, 0), {#253}
- ( 0, 0, 28, 28, 0, 0), {#254}
- ( 0, 0, 0, 0, 0, 0));{#255}
-
- VAR Steigung:BYTE; {determines, which algorithm will be used }
- DY_mal2,DY_m_DX_mal2:INTEGER;
- oldMode:byte;
- regs:registers;
-
- IsAT:BYTE;
- TimeFlag:BYTE;
- CycleTime:LONGINT;
-
- SPRITEAD :ARRAY[0..LoadMAX] OF WORD; {normalized segment addresses }
- SPRITEPTR :ARRAY[0..LoadMAX] OF POINTER; {full 32-bit-pointers }
- SPRITESIZE:ARRAY[0..LoadMAX] OF WORD; {allocated sprite size }
-
- CRTAddress, StatusReg : WORD;
-
- WinLowerRight,WinXMINdiv4,WinYMIN_mul_LINESIZE,
- WinYMINmLINESIZEaWinXMINdiv4:WORD;
- WinWidthDiv4:BYTE;
- BWinXMIN,BWinYMIN,BWinXMAX,BWinYMAX,BWinLowerRight,
- BWinYMIN_mul_LINESIZE:WORD; {backups of all Win* variables}
-
- SplitIndex,SplitIndex_mal2:INTEGER; {split index for sprites & clipping}
-
-
- {-----------------------------------------------------}
-
- PROCEDURE ShadowTab; ASSEMBLER;
- {Pseudo-procedure to store the color lookup table into the code segment }
- {DO NOT TRY TO CALL THIS "PROCEDURE"!!! }
- {default values correspond to a darkening to 70% of the original brightness}
- ASM
- DB 254,104,120,124,112,108,114, 24, 20,128,144, 3,136, 5,140, 7
- DB 254,254, 17, 17, 18, 19, 20, 20, 21, 8, 23, 24, 24, 25, 26, 7
- DB 1, 1,107,108, 5,108,109, 4, 4, 4, 6, 6,116,116,117, 2
- DB 2, 2,123,124, 3,124,125, 1,152,155,156,156, 5,156,156,157
- DB 160,163,164,164,164,164,164,165,168,171,172,172, 3,172,172,173
- DB 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24
- DB 24, 24, 24, 24, 24, 24, 24, 24,176,177,178,179,180,181,182,183
- DB 184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199
- DB 200,201,203,204,204,204,205,207,208,209,211,212,212,212,213,215
- DB 216,217,219,220,220,220,221,223,246,227,228,228,228,228,228,229
- DB 234,235,236,236,236,236,236,237,242,243,244,244,244,244,244,245
- DB 254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254
- DB 254,254,254,254,254,254,254,254, 17, 17, 17, 17, 17, 17, 17, 17
- DB 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17
- DB 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17
- DB 17, 17, 17, 17, 17, 17, 17, 17,254,254,254,254,254,254,254, 7
- END;
-
- PROCEDURE CS_TranslateTab; ASSEMBLER;
- {Small pseudo-procedure to store lookup table for the bitmasks into }
- {the code segment, too}
- ASM
- DB 1,2,4,8
- END;
-
- PROCEDURE SetShadowTab(brightness:BYTE);
- { in: brightness = wanted brightness for the colors in the shadow area, }
- { in percentage of the brightness of the original colors }
- {out: ShadowTab = (best approximation) color table for wanted dimming }
- { Schatten = new brightness (Schatten is a global variable!) }
- {rem: default value of ShadowTab is 70% of the original color brightness! }
- { This routine takes some time (about 4 sec on a 8MHz-AT!) }
-
- VAR neue_Tabelle:ColorTable;
- p1:POINTER;
-
- BEGIN
- IF (brightness<0) OR (brightness>100)
- THEN BEGIN
- Error:=Err_InvalidPercentage;
- exit
- END;
- p1:=@neue_Tabelle; {trick, as the assembler messes up accesses to the SS-segment}
- ASM
- MOV CX,256 {outer loop-counter }
- LES DI,p1 {ES:DI = ^neue_Tabelle[i] }
- MOV SI,OFFSET ActualColors {DS:SI = ^ActualColors[]}
-
- @outerloop:
- LODSB {AL = tempColors[i].red}
- MUL brightness {will be addressed via SS! }
- MOV DL,100
- DIV DL {AL = tempColors[i].red * brightness DIV 100}
- MOV BL,AL {BL := AL = new red part }
-
- LODSB {dto., for green}
- MUL brightness
- MOV DL,100
- DIV DL
- MOV BH,AL {...into BH}
-
- LODSB {dto., for blue}
- MUL brightness
- MOV DL,100
- DIV DL
- MOV DH,AL {...into DH}
-
- {BL / BH / DH = RGB-parts of the color, for which we are seeking an approximation}
- PUSH CX
- PUSH SI
- PUSH DI
- PUSH BP
-
- MOV DI,65535 {min. square of error (up to now) }
- MOV CX,256 {walk through all 256 default colors}
- MOV SI,OFFSET ActualColors {DS:SI = ^ActualColors[]}
- @searchloop:
- MOV AL,BL {compute difference in red part }
- SUB AL,[SI]
- JL @noNewMin {new color may not be brighter! }
- MUL AL {compute square of error}
- MOV BP,AX
-
- MOV AL,BH {dto., for green part}
- SUB AL,[SI+1]
- JL @noNewMin
- MUL AL
- ADD BP,AX
- JC @noNewMin {don't tolerate huge color differences }
-
- MOV AL,DH {dto., for blue part }
- SUB AL,[SI+2]
- JL @noNewMin
- MUL AL
- ADD AX,BP
- JC @noNewMin
-
- CMP AX,DI {did we find a better approximation?}
- JAE @noNewMin {no }
- MOV DI,AX {yes, store square of error and color}
- MOV DL,CL
- OR DI,DI {square of error = 0?}
- JZ @ColorDone {yes, we can't find any better solution than that! }
-
- @noNewMin:
- ADD SI,3
- LOOP @searchloop
-
- CMP DI,65535 {no color found? }
- JNE @ColorDone {but yes, nothing to do!}
- MOV CX,256 {no, thus search again }
- MOV SI,OFFSET ActualColors {DS:SI = ^ActualColors[]}
- @searchloop2:
- LODSB
- SUB AL,BL {Diff ≈±2^6 -> square ≈2^12 -> 3 * square < MaxInt }
- IMUL AL {so no overflow is possible}
- MOV BP,AX
-
- LODSB {dto., for green part}
- SUB AL,BH
- IMUL AL
- ADD BP,AX
-
- LODSB {dto., for blue part }
- SUB AL,DH
- IMUL AL
- ADD AX,BP
-
- CMP AX,DI {did we find a better approximation?}
- JAE @noNewMin2 {no }
- MOV DI,AX {yes, store square of error and color}
- MOV DL,CL
-
- @noNewMin2:
- LOOP @searchloop2
-
-
- @ColorDone: {100h - DL = optimal color found }
- POP BP
- POP DI {ES:DI = ^neue_Tabelle[i] }
- POP SI {DS:SI = ^ActualColors[i] }
- POP CX
-
- MOV AL,DL {store into neue_Tabelle[i] }
- NEG AL {AL = 100h - DL = best approximation}
- STOSB
-
- DEC CX {replacement for "LOOP @outerloop"; next color!}
- JCXZ @fertig
- JMP @outerloop
- @fertig:
-
- END; {of ASM}
- MOVE(neue_Tabelle,@ShadowTab^,256); {activate new color table}
- Schatten:=brightness
- END;
-
- PROCEDURE SetPalette(pal:Palette; update:BOOLEAN);
- { in: pal = pointer to palette to be set }
- { update = TRUE/FALSE for: recompute/don't recompute ShadowTab}
- {out: ActualColors = actual color palette }
- {rem: palette has been set and evtl., ShadowTab has been recomputed }
- BEGIN
- IF @pal<>@ActualColors
- THEN ActualColors:=pal; {copy palette into ActualColors }
- ASM
- MOV SI,OFFSET ActualColors {DS:SI = ^ActualColors[]}
-
- CLI
-
- mov dx,StatusReg
- @WaitNotVSyncLoop:
- in al,dx
- and al,8
- jnz @WaitNotVSyncLoop
- @WaitVSyncLoop:
- in al,dx
- and al,8
- jz @WaitVSyncLoop
-
- MOV DX,3C8h
- XOR AL,AL
- OUT DX,AL
- INC DX
-
- MOV CX,256/2
- @L1:
- LODSW
- OUT DX,AL
- MOV AL,AH
- OUT DX,AL
- LODSW
- OUT DX,AL
- MOV AL,AH
- OUT DX,AL
- LODSW
- OUT DX,AL
- MOV AL,AH
- OUT DX,AL
- LOOP @L1
-
- STI
- END; {of ASM}
- IF update THEN SetShadowTab(Schatten)
- END;
-
- PROCEDURE GetPalette(VAR pal:Palette); ASSEMBLER;
- { in: pal = pointer to palette memory }
- {out: pal = actually set palette }
- ASM
- CLI
- XOR AL,AL
- MOV DX,3C7h
- OUT DX,AL
- LES DI,pal
- MOV CX,768
- MOV DX,3C9h
- @L1:
- IN AL,DX
- STOSB
- LOOP @L1
- STI
- END;
-
- PROCEDURE FadeToPalette(destPal:Palette; AnzSteps:WORD);
- { in: ActualColors = actually set color palette }
- { destPal = destination palette}
- { AnzSteps = number of interleaving steps}
- {out: ActualColors = destPal}
- {rem: The procedure fades from ActualColors to destPal, and it uses }
- { AnzSteps steps to do so}
- { setting of the palette is synchronised to the vertical retrace, }
- { thus each interleaving step lasts 1/70 sec }
- VAR oldColors,pal:Palette;
- i,steps:INTEGER;
- s,d:POINTER;
- BEGIN
- dec(anzsteps);
- IF anzsteps<1
- THEN steps:=1
- ELSE steps:=anzsteps; {bring steps into the same segment as pal}
- oldColors:=ActualColors;
- pal:=destpal; {bring pal and oldColors into the same segment}
- s:=@pal; d:=@ActualColors;
- FOR i:=0 TO steps-1 DO
- BEGIN
- {now use assembler to compute the following sequence:}
- { FOR c:=0 TO 255 DO }
- { BEGIN }
- { ActualColors[c].red:=LONGINT(pal[c].red-oldColors[c].red)*i }
- { DIV steps+ oldColors[c].red; }
- { ActualColors[c].green:=LONGINT(pal[c].green-oldColors[c].green)*i }
- { DIV steps+ oldColors[c].green; }
- { ActualColors[c].blue:=LONGINT(pal[c].blue-oldColors[c].blue)*i }
- { DIV steps+ oldColors[c].blue; }
- { END; }
-
- ASM
- LES DI,d {ES:DI = pointer to ActualColors-table }
- LDS SI,s {DS:SI = pointer to pal-table }
- MOV BX,OFFSET oldColors-OFFSET pal -1 {DS:SI+BX+1 = pointer to oldColors}
-
- MOV CX,256
- @docolor:
- XOR AH,AH
- LODSB {AX := pal[c].red}
- SUB AL,[SI+BX]
- SBB AH,0 {AX := pal[c].red - oldColors[c].red = delta}
- IMUL i {DX:AX := delta * i}
- IDIV steps {AX := delta * i/steps}
- ADD AL,[SI+BX] {AX := delta * i/steps + oldColors[c].red}
- STOSB
-
- {dto. for green}
- XOR AH,AH
- LODSB
- SUB AL,[SI+BX]
- SBB AH,0
- IMUL i
- IDIV steps
- ADD AL,[SI+BX]
- STOSB
-
- {dto. for blue}
- XOR AH,AH
- LODSB
- SUB AL,[SI+BX]
- SBB AH,0
- IMUL i
- IDIV steps
- ADD AL,[SI+BX]
- STOSB
-
- LOOP @docolor
-
- MOV AX,SEG @DATA
- MOV DS,AX
- END;
- SetPalette(ActualColors,FALSE)
- END;
- SetPalette(pal,TRUE)
- END;
-
- FUNCTION LoadPalette(name:String; number:BYTE; VAR pal:Palette):WORD;
- { in: name = name of the palette file (type: "*.PAL") to load }
- { number = number for the first color being read in from the file }
- { ActualColors = actually set color palette }
- {out: number of colors read from the file (0 = an error occured) }
- { pal = color palette read from the file, evtl. filled up}
- {rem: All entries in "pal" which get not overwritten by the file's contents }
- { will become set to the actually set colors of "ActualColors"; the }
- { palette will only become loaded, not actually set!}
- LABEL quitloop;
- VAR len:LONGINT;
- f:FileOfByte;
- i,count:WORD;
- TempPal:Palette;
- flag:BOOLEAN;
- tempName:STRING;
- BEGIN
- count:=0; {number of palette entries read in til now }
- tempName:=FindFile(name);
- IF tempName<>'' THEN name:=tempName;
- _assign(f,name);
- {$I-} _reset(f); {$IFDEF IOcheck} {$I+} {$ENDIF}
- if (ioresult<>0) OR (CompressError<>CompressErr_NoError)
- THEN BEGIN {File doesn't exist or at least not with that path }
- Error:=Err_FileIO;
- CompressError:=CompressErr_NoError;
- LoadPalette:=0; exit
- END;
- len:=_filesize(f); {determine file length}
- if (len mod 3<>0) OR (len>3*256) OR (len<3)
- THEN BEGIN
- Error:=Err_NoPalette;
- goto quitloop;
- END;
- IF len+number*3>3*256
- THEN BEGIN
- Error:=Err_PaletteWontFit;
- goto quitloop;
- END;
-
- TempPal:=ActualColors; {preset temporary palette with actual colors }
- {$I-}
- _blockread(f,TempPal[number],len);
- {$IFDEF IOcheck} {$I+} {$ENDIF}
-
- IF (ioresult<>0) OR (CompressError<>CompressErr_NoError)
- THEN BEGIN
- Error:=Err_FileIO;
- CompressError:=CompressErr_NoError;
- goto quitloop;
- END;
-
- flag:=FALSE;
- FOR i:=number TO Pred(number+(len DIV 3))
- DO flag:=flag OR (TempPal[i].red>63)
- OR (TempPal[i].green>63)
- OR (TempPal[i].blue>63);
- IF flag
- THEN BEGIN
- Error:=Err_NoPalette;
- goto quitloop;
- END;
-
- {everything went alright: return palette}
- pal:=TempPal;
- count:=len DIV 3;
-
- quitloop: ;
- _close(f);
- LoadPalette:=count
- END;
-
- {Now, all the code pieces follow, which can be used to display a sprite; }
- {the interface used is the same for all of them: }
- { in: CX = number of bytes, which have to be copied from... }
- { DS:SI = (pointer to source address) to... }
- { ES:BX = (pointer to destination address) }
- { DI = bitplane (0..3) (=X-coordinate AND 3) }
- { The proper bitmask for selecting the correct write plane has al- }
- { ready been set, but not that for the evtl. needed read plane! }
- { The routines can rely upon CX being <>0 }
- {rem: Every routine MUST CONSIST OF EXACTLY 16 bytes and BE FULLY RELO- }
- { CATIBLE and MAY NOT CHANGE registers BP,DS and ES!!!!!!!!!!!!!!!!! }
- { Besides that, for distinguishtability, the routines must be pair- }
- { wise disjoint in their first two bytes! }
-
- PROCEDURE Modus0; ASSEMBLER;
- {mode 0 considers color 0 being transparent for background data }
- ASM
- INC CX
- STC {change BX such that (together with SI) it can be }
- SBB BX,SI {used for accessing the target address}
- @L1:
- LODSB {fetch sprite byte }
- OR AL,AL {is it zero? }
- LOOPZ @L1 {yes, ignore it }
- JCXZ @L2 {all bytes done? }
- MOV ES:[BX+SI],AL {no, store to screen }
- JMP @L1 {short} {work on next byte }
- @L2:
- END;
-
- PROCEDURE Modus1; ASSEMBLER;
- {mode 1 writes the data directly to the screen, without further processing }
- ASM
- MOV DI,BX {set DI so that the string instructions can be used }
- XOR AX,AX {set AX := 0 }
- SHR CX,1 {number of words to move }
- REP MOVSW {move data as one block at once }
- ADC CX,AX {does a single byte remain? }
- REP MOVSB
- MOV AX,AX {4 filling bytes; faster than 4 NOPs}
- MOV AX,AX
- END;
-
- PROCEDURE Modus2Work; ASSEMBLER;
- {Continuation of mode2 - everything, which didn't fit in the reserved 16 }
- {bytes is placed here}
- ASM
- OUT DX,AX {enable read access for correct plane }
-
- PUSH DS {DS still points to sprite data, but must }
- {point to background! }
- MOV AX,ES {DS:SI := ES:DI (source ptr:=dest. ptr) }
- MOV DS,AX
- MOV SI,DI
- MOV BX,OFFSET ShadowTab {set pointer to color lookup table }
-
- @L4:
- LODSB {get background color... }
- SEGCS XLAT {...use color lookup table to transform}
- STOSB {...and display on actual graphic page}
- LOOP @L4
-
- POP DS
- END;
-
- PROCEDURE Modus2; ASSEMBLER;
- {mode 2 is thought for "shadows" and the like: the sprite's data itself }
- {will be ignored; instead, the background data underneath the sprite's }
- {position is read in and these color values will be exchanged against }
- {those of the color lookup table "ShadowTab" (e.g.: to realize shadows, }
- {this table should hold a darker color for each of the original colors) }
- ASM
- MOV AX,DI {bring bitplane for read access to AX }
- MOV DI,BX {put dest. addr. into DI for 8086's string instructions}
- MOV AH,AL {bring bitplane to highbyte }
- MOV AL,4
- MOV DX,3CEh
- MOV SI,OFFSET Modus2Work {sort of hack: "CALL Modus2Work" would be coded }
- CALL SI {RELATIVE - and thus, jump to ever-neverland! }
- END;
-
- PROCEDURE Modus3Work; ASSEMBLER;
- {continuation of Modus3 - everything, which didn't fit into 16 bytes }
- {bytes is placed here}
- ASM
- STC
- SBB BX,SI {address source and destination with only 1 index register}
- MOV DX,BP {save BP-register }
- MOV BP,BX
- MOV BX,OFFSET ShadowTab {set pointer to color lookup table }
-
- @L1:
- LODSB {get sprite data... }
- OR AL,AL { (ignore color 0 as "transparent") }
- LOOPZ @L1
- JCXZ @L2
- MOV AL,ES:[BP+SI] {get background color... }
- SEGCS XLAT {...use color lookup table to transform}
- MOV ES:[BP+SI],AL {...and display on actual graphic page}
- JMP @L1
- @L2:
- MOV BP,DX {restore old contents of BP register }
- END;
-
- PROCEDURE Modus3; ASSEMBLER;
- {Modus3 is thought for "shadows", too: in this mode, all sprite }
- {pixels with color <>0 will be processed: the background color, which is }
- {underneath these pixels will be replaced by the corresponding color entry }
- {from the table "ShadowTab" }
- {in other words: this mode is the same as mode 2, with the difference, that }
- {sprite color 0 is treated as being transparent for shadows! }
- ASM
- MOV DX,3CEh {prepare access to read plane: }
- MOV AX,DI
- MOV AH,AL {load read plane into AH }
- MOV AL,4
- OUT DX,AX {enable read access for correct plane }
- INC CX {inc. number of bytes by 1 (-> LODSB!) }
- MOV AX,OFFSET Modus3Work {trick to make code relocatible! }
- CALL AX
- END;
-
- PROCEDURE Adressen; ASSEMBLER;
- {table with the starting addresses of the 3 routines in the code segment}
- ASM
- DW OFFSET Modus0
- DW OFFSET Modus1
- DW OFFSET Modus2
- DW OFFSET Modus3
- END;
-
-
- PROCEDURE GADR; ASSEMBLER;
- {table with graphic rows starting addresses (offset part)}
- ASM
- DW $0000,$0050,$00A0,$00F0,$0140,$0190,$01E0,$0230
- DW $0280,$02D0,$0320,$0370,$03C0,$0410,$0460,$04B0
- DW $0500,$0550,$05A0,$05F0,$0640,$0690,$06E0,$0730
- DW $0780,$07D0,$0820,$0870,$08C0,$0910,$0960,$09B0
- DW $0A00,$0A50,$0AA0,$0AF0,$0B40,$0B90,$0BE0,$0C30
- DW $0C80,$0CD0,$0D20,$0D70,$0DC0,$0E10,$0E60,$0EB0
- DW $0F00,$0F50,$0FA0,$0FF0,$1040,$1090,$10E0,$1130
- DW $1180,$11D0,$1220,$1270,$12C0,$1310,$1360,$13B0
- DW $1400,$1450,$14A0,$14F0,$1540,$1590,$15E0,$1630
- DW $1680,$16D0,$1720,$1770,$17C0,$1810,$1860,$18B0
- DW $1900,$1950,$19A0,$19F0,$1A40,$1A90,$1AE0,$1B30
- DW $1B80,$1BD0,$1C20,$1C70,$1CC0,$1D10,$1D60,$1DB0
- DW $1E00,$1E50,$1EA0,$1EF0,$1F40,$1F90,$1FE0,$2030
- DW $2080,$20D0,$2120,$2170,$21C0,$2210,$2260,$22B0
- DW $2300,$2350,$23A0,$23F0,$2440,$2490,$24E0,$2530
- DW $2580,$25D0,$2620,$2670,$26C0,$2710,$2760,$27B0
- DW $2800,$2850,$28A0,$28F0,$2940,$2990,$29E0,$2A30
- DW $2A80,$2AD0,$2B20,$2B70,$2BC0,$2C10,$2C60,$2CB0
- DW $2D00,$2D50,$2DA0,$2DF0,$2E40,$2E90,$2EE0,$2F30
- DW $2F80,$2FD0,$3020,$3070,$30C0,$3110,$3160,$31B0
- DW $3200,$3250,$32A0,$32F0,$3340,$3390,$33E0,$3430
- DW $3480,$34D0,$3520,$3570,$35C0,$3610,$3660,$36B0
- DW $3700,$3750,$37A0,$37F0,$3840,$3890,$38E0,$3930
- DW $3980,$39D0,$3A20,$3A70,$3AC0,$3B10,$3B60,$3BB0
- DW $3C00,$3C50,$3CA0,$3CF0,$3D40,$3D90,$3DE0,$3E30
- DW $3E80
- END;
-
- FUNCTION EMSinstalled(VAR PageFrameSeg:WORD):Boolean;
- { in: - }
- {out: PageFrameSeg = segment address of EMS-frame }
- { TRUE/FALSE for: EMS installed/not installed }
- { Error, EMSError = evtl. error code}
- {rem: If USEEMS=FALSE, the return value will always be FALSE }
- TYPE Tag=ARRAY[1..8] OF CHAR;
- VAR p:POINTER;
- Begin
- EMSError:=0;
- IF NOT USEEMS
- THEN BEGIN
- EMSinstalled:=FALSE;
- exit
- END;
- GetIntVec(EMSInt,p);
- IF Tag(Ptr(SEG(p^),$A)^)='EMMXXXX0'
- THEN BEGIN {EMS-driver exists, but ist must be at least V3.2:}
- WITH Regs DO
- BEGIN
- AH:=$46; Intr(EMSInt,Regs); {fetch version number}
- EMSInstalled:=AL>=$32; {version >= 3.2 ? }
-
- AH:=$41; Intr(EMSInt,Regs); {BX=segment address, AH=evtl. error}
- PageFrameSeg:=BX;
- EmsError:=AH;
- IF EmsError<>0 THEN Error:=Err_EMSError;
- END;
- END
- ELSE EMSInstalled:=FALSE
- End;
-
- FUNCTION EMSPagesAvailable:WORD;
- { in: - }
- {out: returns number of available EMS pages (each one = 16K)}
- { Error, EMSError = evtl. error code}
- {rem: only call this routine, if EMSinstalled = TRUE!}
- BEGIN
- WITH Regs DO
- BEGIN
- AH:=$42; Intr(EMSInt,Regs); {determine number of available pages}
- EMSPagesAvailable:=BX;
- EmsError := AH;
- IF EmsError<>0 THEN Error:=Err_EMSError;
- END;
- END;
-
- FUNCTION EMSAllocate(pages:Word):WORD;
- { in: pages = #number of pages to allocate}
- {out: handle to this EMS-block }
- { Error, EMSError = evtl. error code}
- {rem: pages may not exceed the number of available pages PagesAvail!}
- BEGIN
- With Regs do
- BEGIN
- AH:=$43;
- BX:=pages;
- Intr(EMSInt,Regs);
- EmsError := AH;
- IF EmsError<>0 THEN Error:=Err_EMSError;
- EMSAllocate := DX;
- END;
- END;
-
- Procedure EMSSwapPageIn(EMSHandle, LogicNr,PhysicalNr:Word);
- { in: EMSHandle = handle to an allocated EMS-block }
- { LogicNr = logical page number within that EMS-block }
- { PhysicalNr = physical page number of the EMS-frame (=0..3) }
- {out: Error, EMSError = evtl. error code}
- {rem: Maps the logical page "LogicNr" of the EMS-area, which has been }
- { allocated with the handle "EMSHandle" into the physical EMS-page }
- { "PhysicalNr"}
- { Afterwards, accesses of the form MEM[BACKGNDADR:PhysicalNr*$4000] }
- { are possible}
- { PhysicalNr = 0..3}
- { LogicNr = 0..allocated number of pages-1}
- BEGIN
- With Regs do
- BEGIN
- AH:=$44; DX:=EMSHandle; BX:=LogicNr; AL:=PhysicalNr;
- Intr(EMSInt,Regs);
- EmsError := AH;
- IF EmsError<>0 THEN Error:=Err_EMSError;
- END;
- END;
-
- PROCEDURE EMSFillFrame(EMSHandle:WORD);
- { in: EMSHandle = handle to the EMS-frame (4 pages in size)}
- {out: EMS-frame-buffer has been filled with the first 4 pages}
- { Error, EMSError = evtl. error code}
- CONST a:ARRAY[0..7] OF WORD=(0,0,1,1,2,2,3,3);
- BEGIN
- With Regs do
- BEGIN
- AX:=$5000; DX:=EMSHandle; CX:=4;
- DS:=Seg(a); SI:=Ofs(a);
- Intr(EMSInt,Regs);
- EmsError := AH;
- IF EmsError<>0 THEN Error:=Err_EMSError;
- END;
- END;
-
- PROCEDURE EMSRelease(handle:WORD);
- { in: handle = handle to the EMS-block to release }
- {out: Error, EMSError = evtl. error code}
- {rem: EMS-block has been released}
- BEGIN
- With Regs do
- BEGIN
- AH:=$45;
- DX:=handle;
- Intr(EMSInt,Regs);
- EmsError:=AH;
- IF EmsError<>0 THEN Error:=Err_EMSError;
- END;
- END;
-
- FUNCTION EMSIsHardwareEMS:BOOLEAN;
- { in: - }
- {out: FALSE, if EMS is only simulated }
- { Error, EMSError = evtl. error code}
- {rem: This check is done as suggested in the LIM4.0-specifications: }
- { one logical page is mapped into all physical pages and then the }
- { resulting configuration is checked}
- CONST a:ARRAY[0..7] OF WORD=(0,0,0,1,0,2,0,3);
- VAR SegAdr,handle:WORD;
- mirror:BOOLEAN;
- BEGIN
- IF NOT(EMSInstalled(SegAdr)) OR (EMSPagesAvailable<1)
- THEN EMSIsHardwareEMS:=TRUE {someone having a better idea?}
- ELSE BEGIN
- handle:=EMSAllocate(1);
- With Regs do
- BEGIN {map logical page #0 into all 4 physical pages }
- AX:=$5000; DX:=handle; CX:=4;
- DS:=Seg(a); SI:=Ofs(a);
- Intr(EMSInt,Regs);
- EmsError := AH;
- IF EmsError<>0 THEN Error:=Err_EMSError;
- END;
- MEM[SegAdr:16383]:=0;
- mirror:=(MEM[SegAdr:1*16384+16383] OR
- MEM[SegAdr:2*16384+16383] OR
- MEM[SegAdr:3*16384+16383])=0;
- MEM[SegAdr:16383]:=$FF;
- mirror:=mirror AND
- ((MEM[SegAdr:1*16384+16383] AND
- MEM[SegAdr:2*16384+16383] AND
- MEM[SegAdr:3*16384+16383])=$FF);
- EMSRelease(handle);
- EMSIsHardWareEMS:=mirror
- END;
- END;
-
- PROCEDURE EnsureEMSConsistency(EMSHandle:WORD);
- { in: EMSused = TRUE}
- { EMSHandle = handle of allocated EMS-block }
- { BACKGNDADR:0 = start of EMS-frame }
- {out: The EMS-frame is filled with the wanted 64K data}
- BEGIN
- EMSFillFrame(EMSHandle); {prepare EMS access }
- END;
-
- FUNCTION AT:BOOLEAN;
- { in: - }
- {out: TRUE/FALSE, if the machine is (at least) an AT }
- BEGIN
- AT:=MEM[$F000:$FFFE]=$FC
- END;
-
-
- PROCEDURE SetCycleTime(milliseconds:WORD);
- { in: min. time for one animation cycle in milliseconds }
- {out: CycleTime := that value in microseconds }
- { TimeFlag := $80}
- {rem: Because of TimeFlag:=$80, the timing mechanism won't work }
- { for the very first animation cycle, yet! }
- { If you don't use the timing mechanism (by supplying a value}
- { of 0 milliseconds), this will result in IsAT:=$80, that is }
- { the routine will fake "computer is a PC". Else IsAT=0 }
- BEGIN
- TimeFlag:=$80;
- CycleTime:=LONGINT(milliseconds)*LONGINT(1000);
- IF (milliseconds<>0) AND AT
- THEN IsAT:=0 {yes, time control mechanism shall be used }
- ELSE IsAT:=$80 {no, none possible or not wanted }
- END;
-
- PROCEDURE SetSpriteCycle(nr,len:WORD);
- { in: nr = spriteloadnumber of the first sprite in the cycle }
- { len = length of your sprite cycle }
- {out: NextSprite[nr] through NextSprite[nr+len-1] have been set }
- { set such that they build a "ring", that is: together }
- { they make up a sprite cycle}
- {rem: If the sprite cycle shall consist of (physical) sprites }
- { whose load numbers aren't consecutive, then you }
- { have to make the appropriate entries into NextSprite[] }
- { yourself manually }
- { This routine uses spriteLOADnumbers! }
- VAR i:WORD;
- BEGIN
- IF (nr<1) OR (nr+len-1>LoadMAX)
- THEN Error:=Err_InvalidSpriteLoadNumber
- ELSE BEGIN
- FOR i:=nr TO nr+len-2 DO NextSprite[i]:=SUCC(i);
- NextSprite[PRED(nr+len)]:=nr {last sprite points to first one}
- END;
- END;
-
-
- FUNCTION GetImage(x1,y1,x2,y2:INTEGER; pa:WORD):POINTER;
- { in: (x1,y1) = upper left corner of the area which shall be stored }
- { (x2,y2) = according lower right corner (in virtual coordinates!) }
- { pa = graphic page from which the image should be taken (0..3) }
- { StartVirtualX,StartVirtualY = upper left image corner }
- {out: pointer to heap address where the copied screen area is stored }
- { left_cut= evtl. needed left cut off of the image (this determines, }
- { how many pixels at the left edge of the image lie outside }
- { of the screen) }
- { right_cut, top_cut, bottom_cut = dto., for other edges }
- { was_cut = TRUE/FALSE, if it was necessary/not necessary to clip the }
- { fetched image }
- {rem: The memory needed will be reserved by the routine automatically }
- { If that is impossible (or the image is completely offscreen), the }
- { routine will return NIL! }
- { Only if "was_cut" is set to TRUE, the (global) "..._cut" variables }
- { will be set to something other then 0, that is: if the window lies }
- { _completely_ offscreen (this means: returned ptr=NIL), then the }
- { routine still returns "was_cut"=FALSE!}
- VAR len,breite,hoehe,StartAdr,actualAdr,SegmAdr:WORD;
- p:POINTER;
- BEGIN
- was_cut:=FALSE; left_cut:=0; right_cut:=0; top_cut:=0; bottom_cut:=0;
- dec(x1,StartVirtualX); {compute screen coordinates }
- dec(y1,StartVirtualY);
- IF (x1>XMAX) or (y1>YMAX) or (x2<0) or (y2<0) or (x1>x2) or (y1>y2)
- THEN BEGIN {window is offscreen }
- GetImage:=NIL;
- exit
- END;
- {cut clipping according to visible screen:}
- IF x1<0 THEN BEGIN left_cut :=-x1; x1:=0; was_cut:=TRUE END;
- IF y1<0 THEN BEGIN top_cut:=-y1; y1:=0; was_cut:=TRUE END;
- IF x2>XMAX THEN BEGIN right_cut :=x2-XMAX; x2:=XMAX; was_cut:=TRUE END;
- IF y2>YMAX THEN BEGIN bottom_cut:=y2-YMAX; y2:=YMAX; was_cut:=TRUE END;
-
- breite:=SUCC(x2-x1); hoehe:=SUCC(y2-y1);
- len:=breite*hoehe+2*2; {1 pixel = 1 byte; add 2 words for width & height }
- IF len>MaxAvail
- THEN BEGIN
- Error:=Err_NotEnoughMemory;
- GetImage:=NIL;
- exit
- END;
- IF (pa<0) OR (pa>SCROLLPAGE) {page number must be 0..3 }
- THEN BEGIN
- Error:=Err_InvalidPageNumber;
- GetImage:=NIL;
- exit
- END
- ELSE SegmAdr:=Segment_Adr[pa];
- GetMem(p,len); {get memory from the heap }
- IF pa<>BACKGNDPAGE
- THEN ASM {VRAM to RAM }
- CLD
- LES DI,p {ES:DI = pointer to the acquired memory }
- MOV AX,breite
- STOSW {store width first... }
- MOV AX,hoehe
- STOSW {...then store height, followed by the data }
-
- MOV BX,AX {BX := hoehe (to be used later) }
- MOV SI,y1
- SHL SI,1
- MOV SI,CS:[OFFSET gadr + SI] {SI := y1 * LINESIZE}
- MOV AX,x1
- MOV DL,AL
- SHR AX,1
- SHR AX,1
- ADD SI,AX {SI := offset part of the start address}
- MOV StartAdr,SI
- MOV actualAdr,SI
- AND DL,3
- MOV AH,DL
- MOV AL,4
- MOV DX,3CEh
- OUT DX,AX {select start plane }
- MOV DS,SegmAdr
-
- {DS:SI = pointer to first byte to store; ES:DI = its target address }
- {AH = startplane, AL = 4, BX = number of rows to process }
-
- MOV DX,breite
- ADD DX,3
- SHR DX,1
- SHR DX,1 {DX = number of bytes to store for each row}
-
- @L1:
- MOV CX,DX {store data of one row }
- SHR CX,1 {faster than "REP MOVSB" }
- REP MOVSW
- ADC CX,CX
- REP MOVSB
- MOV SI,actualAdr {increment source pointer by 1 graphic row}
- ADD SI,LINESIZE
- MOV actualAdr,SI
- DEC BX {decrease row counter }
- JNE @L1
-
- INC AH {select next plane }
- CMP AH,4
- JNE @nowrap1 {wrapping the bitplane means: start address }
- MOV AH,0 {needs mending: increment address by 1! }
- INC StartAdr
- @nowrap1:
- MOV DX,3CEh
- OUT DX,AX
- MOV BX,hoehe
- MOV DX,breite
- INC DX
- INC DX
- SHR DX,1
- SHR DX,1
- MOV SI,StartAdr
- MOV actualAdr,SI
-
- @L2:
- MOV CX,DX
- SHR CX,1 {faster than "REP MOVSB" }
- REP MOVSW
- ADC CX,CX
- REP MOVSB
- MOV SI,actualAdr
- ADD SI,LINESIZE
- MOV actualAdr,SI
- DEC BX
- JNE @L2
-
- INC AH
- CMP AH,4
- JNE @nowrap2
- MOV AH,0
- INC StartAdr
- @nowrap2:
- MOV DX,3CEh
- OUT DX,AX
- MOV BX,hoehe
- MOV DX,breite
- INC DX
- SHR DX,1
- SHR DX,1
- MOV SI,StartAdr
- MOV actualAdr,SI
-
- @L3:
- MOV CX,DX
- SHR CX,1 {faster than "REP MOVSB" }
- REP MOVSW
- ADC CX,CX
- REP MOVSB
- MOV SI,actualAdr
- ADD SI,LINESIZE
- MOV actualAdr,SI
- DEC BX
- JNE @L3
-
- INC AH
- CMP AH,4
- JNE @nowrap3
- MOV AH,0
- INC StartAdr
- @nowrap3:
- MOV DX,3CEh
- OUT DX,AX
- MOV BX,hoehe
- MOV DX,breite
- SHR DX,1
- SHR DX,1
- MOV SI,StartAdr
- MOV actualAdr,SI
-
- @L4:
- MOV CX,DX
- SHR CX,1 {faster than "REP MOVSB" }
- REP MOVSW
- ADC CX,CX
- REP MOVSB
- MOV SI,actualAdr
- ADD SI,LINESIZE
- MOV actualAdr,SI
- DEC BX
- JNE @L4
-
- MOV AX,SEG @DATA
- MOV DS,AX
- END
- ELSE BEGIN
- IF EMSused
- THEN EMSFillFrame(BackgroundEMSHandle); {prepare EMS access }
- ASM {RAM to RAM }
- CLD
- LES DI,p {ES:DI = pointer to the acquired memory }
- MOV AX,breite
- STOSW {store width first... }
- MOV AX,hoehe
- STOSW {...then store height, followed by the data }
-
- MOV DX,AX {DX := hoehe (to be used later) }
- MOV SI,y1
- SHL SI,1
- MOV SI,CS:[OFFSET gadr + SI] {SI := y1 * LINESIZE}
- MOV AX,x1
- MOV BL,AL
- SHR AX,1
- SHR AX,1
- ADD SI,AX {SI := offset part of the start address}
- AND BX,3
- MOV AH,BL
- SHL BX,1
- ADD SI,[OFFSET BACKTab + BX] {select start plane }
- MOV StartAdr,SI
- MOV actualAdr,SI
- MOV DS,SegmAdr
- MOV BX,DX
-
- {DS:SI = pointer to first byte to store; ES:DI = its target address }
- {AH = startplane, BX = number of rows to process }
-
- MOV DX,breite
- ADD DX,3
- SHR DX,1
- SHR DX,1 {DX = number of bytes to store for each row}
-
- @L1:
- MOV CX,DX {store data of one row }
- SHR CX,1 {faster than "REP MOVSB" }
- REP MOVSW
- ADC CX,CX
- REP MOVSB
- MOV SI,actualAdr {increment source pointer by 1 graphic row}
- ADD SI,LINESIZE
- MOV actualAdr,SI
- DEC BX {decrease row counter }
- JNE @L1
-
- INC AH {select next plane }
- ADD StartAdr,PAGESIZE
- CMP AH,4
- JNE @nowrap1 {wrapping the bitplane means: start address }
- MOV AH,0 {needs mending: increment address by 1! }
- SUB StartAdr,4*PAGESIZE -1
- @nowrap1:
- MOV BX,hoehe
- MOV DX,breite
- INC DX
- INC DX
- SHR DX,1
- SHR DX,1
- MOV SI,StartAdr
- MOV actualAdr,SI
-
- @L2:
- MOV CX,DX
- SHR CX,1 {faster than "REP MOVSB" }
- REP MOVSW
- ADC CX,CX
- REP MOVSB
- MOV SI,actualAdr
- ADD SI,LINESIZE
- MOV actualAdr,SI
- DEC BX
- JNE @L2
-
- INC AH
- ADD StartAdr,PAGESIZE
- CMP AH,4
- JNE @nowrap2
- MOV AH,0
- SUB StartAdr,4*PAGESIZE -1
- @nowrap2:
- MOV BX,hoehe
- MOV DX,breite
- INC DX
- SHR DX,1
- SHR DX,1
- MOV SI,StartAdr
- MOV actualAdr,SI
-
- @L3:
- MOV CX,DX
- SHR CX,1 {faster than "REP MOVSB" }
- REP MOVSW
- ADC CX,CX
- REP MOVSB
- MOV SI,actualAdr
- ADD SI,LINESIZE
- MOV actualAdr,SI
- DEC BX
- JNE @L3
-
- INC AH
- ADD StartAdr,PAGESIZE
- CMP AH,4
- JNE @nowrap3
- MOV AH,0
- SUB StartAdr,4*PAGESIZE -1
- @nowrap3:
- MOV BX,hoehe
- MOV DX,breite
- SHR DX,1
- SHR DX,1
- MOV SI,StartAdr
- MOV actualAdr,SI
-
- @L4:
- MOV CX,DX
- SHR CX,1 {faster than "REP MOVSB" }
- REP MOVSW
- ADC CX,CX
- REP MOVSB
- MOV SI,actualAdr
- ADD SI,LINESIZE
- MOV actualAdr,SI
- DEC BX
- JNE @L4
-
- MOV AX,SEG @DATA
- MOV DS,AX
- END;
- END;
- GetImage:=p
- END;
-
- PROCEDURE PutImage(x,y:INTEGER; p:POINTER; pa:WORD);
- { in: (x,y) = upper left corner of destination (virtual coordinates) }
- { p = pointer to the cutting (returned by GetImage) }
- { pa = graphic page to which the cutting shall be pasted to }
- { StartVirtualX,StartVirtualY = upper left image corner }
- {out: - }
- {rem: The cutting has been properly clipped before being displayed }
- { If you supply NIL as pointer, the routine will display nothing }
- { That is useful when you are going to use the routine directly on }
- { the return value of GetImage!}
- VAR breite,hoehe,SegmAdr,actualAdr,StartAdr,breite1,breite2,breite3,breite4,
- licut_div4,topcut,pl_adr1,pl_adr2,pl_adr3,pl_adr4:WORD;
- licutoff,temp:INTEGER;
- BEGIN
- IF p=NIL THEN exit;
- dec(x,StartVirtualX); {compute screen coordinates }
- dec(y,StartVirtualY);
- IF (x>XMAX) or (y>YMAX) THEN exit;
- IF (pa<0) OR (pa>SCROLLPAGE)
- THEN BEGIN
- Error:=Err_InvalidPageNumber;
- exit
- END
- ELSE SegmAdr:=Segment_Adr[pa];
- breite:=MEMW[SEG(p^):OFS(p^)];
- hoehe :=MEMW[SEG(p^):OFS(p^)+2];
- IF (x+breite<=0) or (y+hoehe<=0) THEN exit;
- IF x<0 THEN BEGIN licutoff:=-x; x:=0 END
- ELSE licutoff:=0;
- IF y<0 THEN BEGIN
- topcut:=-y;
- y:=0
- END
- ELSE topcut:=0;
-
- breite1:=(breite + 3) shr 2; {Width of a row for the first, second, }
- breite2:=(breite + 2) shr 2; {third and fourth bitplane, respectively}
- breite3:=(breite + 1) shr 2;
- breite4:=(breite + 0) shr 2;
-
- {Compute starting addresses of the 4 bitplanes; take into account evtl. }
- {left cutoff (+4 bytes to jump over "breite" (width) and "hoehe" (height) }
- licut_div4:=licutoff shr 2;
- pl_adr1:=4 +licut_div4 +topcut*breite1;
- pl_adr2:=4 +licut_div4 +topcut*breite2 +hoehe*breite1;
- pl_adr3:=4 +licut_div4 +topcut*breite3 +hoehe*(breite1+breite2);
- pl_adr4:=4 +licut_div4 +topcut*breite4 +hoehe*(breite1+breite2+breite3);
-
- {licutoff mod 4 determines the order in which the points must be read }
- {of the heap: 0 = plane order (1,2,3,4); 1 = plane order (2,3,4,1); }
- {note that the widths of the bitplane tables }
- {are (and remain) linked to these; therefore, they will be swapped }
- {to accomplish that! }
- ASM
- CLD
- MOV AX,licutoff
- AND AL,3
- OR AL,AL
- JE @no_exchange
- CMP AL,1
- JNE @L10
-
- MOV AX,pl_adr2 {displacement of 1 bit: }
- MOV BX,pl_adr3 {AX = Plane2, BX = Plane3, CX = Plane4, DX = Plane1}
- MOV CX,pl_adr4
- MOV DX,pl_adr1 {wrap-around, thus: increment address by 1, which }
- INC DX {corresponds to an ajustment of 4 points }
- MOV pl_adr1,AX {(e.g.: pixels (1,5,9,...),(2,6,10,...),(3,7,11,...)}
- MOV pl_adr2,BX {and (0,4,8,...); the last bitplane needs a cor- }
- MOV pl_adr3,CX {rection of +1 byte: this results in (4,8,12,...) }
- MOV pl_adr4,DX {(read planes top-down, in alternating order!) }
- MOV AX,breite2 {Now the plane widths: }
- MOV BX,breite3 {AX = Plane2, BX = Plane3, CX = Plane4, DX = Plane1}
- MOV CX,breite4
- MOV DX,breite1
- JMP @store
-
- @L10:
- CMP AL,2
- JNE @L20
-
- MOV AX,pl_adr3 {displacement of 2 bit: }
- MOV BX,pl_adr4 {AX = Plane3, BX = Plane4, CX = Plane1, DX = Plane2}
- MOV CX,pl_adr1
- INC CX
- MOV DX,pl_adr2
- INC DX
- MOV pl_adr1,AX
- MOV pl_adr2,BX
- MOV pl_adr3,CX
- MOV pl_adr4,DX
- MOV AX,breite3 {dto. for plane widths: }
- MOV BX,breite4 {AX = Plane3, BX = Plane4, CX = Plane1, DX = Plane2}
- MOV CX,breite1
- MOV DX,breite2
- JMP @store
- @L20:
- MOV AX,pl_adr4 {displacement of 3 bit: }
- MOV BX,pl_adr1 {AX = Plane4, BX = Plane1, CX = Plane2, DX = Plane3}
- INC BX
- MOV CX,pl_adr2
- INC CX
- MOV DX,pl_adr3
- INC DX
- MOV pl_adr1,AX
- MOV pl_adr2,BX
- MOV pl_adr3,CX
- MOV pl_adr4,DX
- MOV AX,breite4 {dto. for plane widths: }
- MOV BX,breite1 {AX = Plane4, BX = Plane1, CX = Plane2, DX = Plane3}
- MOV CX,breite2
- MOV DX,breite3
- @store:
- MOV breite1,AX
- MOV breite2,BX
- MOV breite3,CX
- MOV breite4,DX
-
- @no_exchange: {precondition here: (pl_adr?,breite?) contain the }
- {source bitplanes/-widths in the correct order }
-
- MOV AX,topcut
- SUB hoehe,AX {evtl. adjust height for upper cutoff }
- MOV AX,licutoff
- SUB breite,AX {dto. for width and left cutoff }
-
- MOV AX,x {if image would spread over the right screen }
- ADD AX,breite {boundary: compute right cutoff }
- SUB AX,XMAX+1
- JLE @no_recutoff
- SUB breite,AX {cut off AX points at the right}
- @no_recutoff:
-
- MOV AX,y {exactly the same for the lower screen border}
- ADD AX,hoehe
- SUB AX,YMAX+1
- JLE @no_bocutoff
- SUB hoehe,AX {cut off AX rows at the bottom}
- @no_bocutoff:
- END;
-
- IF pa<>BACKGNDPAGE
- THEN ASM {RAM to VRAM }
- LDS SI,p
- ADD pl_adr2,SI {add pointer's offset part to the plane address }
- ADD pl_adr3,SI
- ADD pl_adr4,SI
-
- ADD SI,pl_adr1 {width, height and parts above the screen }
- MOV ES,SegmAdr
-
- MOV DI,y
- SHL DI,1
- MOV DI,CS:[OFFSET gadr + DI] {DI := y * LINESIZE}
- MOV AX,x
- MOV BL,AL
- SHR AX,1
- SHR AX,1
- ADD DI,AX {DI := y * LINESIZE + (x DIV 4)}
- MOV StartAdr,DI
- MOV actualAdr,DI
-
- AND BX,3 {startplane := x mod 3}
- MOV AH,CS:[OFFSET CS_TranslateTab + BX]
- MOV AL,2
- MOV DX,3C4h
- OUT DX,AX {use it as write plane }
-
- MOV DX,hoehe
- MOV DI,actualAdr
-
- {DS:SI = pointer to data, ES:DI = dest. address on screen for them }
- {AH = bitmask for access, AL = 2 }
- MOV BX,breite
- ADD BX,3
- SHR BX,1
- SHR BX,1
- mov cx,bx
- @L1:
- push si
- SHR CX,1 {faster than "REP MOVSB" }
- REP MOVSW
- ADC CX,CX
- REP MOVSB
- pop si
- mov cx,bx
- add si,breite1
- MOV DI,actualAdr
- ADD DI,LINESIZE
- MOV actualAdr,DI
- DEC DX
- JNE @L1
-
-
- SHL AH,1 {select next bitplane; if wrap-around occurs }
- CMP AH,16 {from bitplane 3 to bitplane 0, then the start-}
- JNE @nowrap1 {ing address must be incremented by 1 byte }
- MOV AH,1
- INC StartAdr
- @nowrap1:
- MOV DX,3C4h
- OUT DX,AX
- MOV SI,pl_adr2
- MOV DI,StartAdr
- MOV actualAdr,DI
- MOV DX,hoehe
- MOV BX,breite
- INC BX
- INC BX
- SHR BX,1
- SHR BX,1
- mov cx,bx
- @L2:
- push si
- SHR CX,1 {faster than "REP MOVSB" }
- REP MOVSW
- ADC CX,CX
- REP MOVSB
- pop si
- mov cx,bx
- add si,breite2
- MOV DI,actualAdr
- ADD DI,LINESIZE
- MOV actualAdr,DI
- DEC DX
- JNE @L2
-
-
- SHL AH,1
- CMP AH,16
- JNE @nowrap2
- MOV AH,1
- INC StartAdr
- @nowrap2:
- MOV DX,3C4h
- OUT DX,AX
- MOV SI,pl_adr3
- MOV DI,StartAdr
- MOV actualAdr,DI
- MOV DX,hoehe
- MOV BX,breite
- INC BX
- SHR BX,1
- SHR BX,1
- mov cx,bx
- @L3:
- push si
- SHR CX,1 {faster than "REP MOVSB" }
- REP MOVSW
- ADC CX,CX
- REP MOVSB
- pop si
- mov cx,bx
- add si,breite3
- MOV DI,actualAdr
- ADD DI,LINESIZE
- MOV actualAdr,DI
- DEC DX
- JNE @L3
-
-
- SHL AH,1
- CMP AH,16
- JNE @nowrap3
- MOV AH,1
- INC StartAdr
- @nowrap3:
- MOV DX,3C4h
- OUT DX,AX
- MOV SI,pl_adr4
- MOV DI,StartAdr
- MOV actualAdr,DI
- MOV DX,hoehe
- MOV BX,breite
- SHR BX,1
- SHR BX,1
- mov cx,bx
- @L4:
- push si
- SHR CX,1 {faster than "REP MOVSB" }
- REP MOVSW
- ADC CX,CX
- REP MOVSB
- pop si
- mov cx,bx
- add si,breite4
- MOV DI,actualAdr
- ADD DI,LINESIZE
- MOV actualAdr,DI
- DEC DX
- JNE @L4
-
- MOV AX,SEG @DATA
- MOV DS,AX
- END
- ELSE BEGIN
- IF EMSused
- THEN EMSFillFrame(BackgroundEMSHandle); {prepare EMS access }
- ASM {RAM to RAM }
- MOV AX,DS
- MOV ES,AX {ES := old data segment }
-
- LDS SI,p
- ADD pl_adr2,SI {add pointer's offset part to the plane address }
- ADD pl_adr3,SI
- ADD pl_adr4,SI
-
- ADD SI,pl_adr1 {width, height and parts above the screen }
-
- MOV DI,y
- SHL DI,1
- MOV DI,CS:[OFFSET gadr + DI] {DI := y * LINESIZE}
- MOV AX,x
- MOV BL,AL
- SHR AX,1
- SHR AX,1
- ADD DI,AX {DI := y * LINESIZE + (x DIV 4)}
-
- AND BX,3 {startplane := x mod 3}
- MOV AL,BL {store copy to AL }
- SHL BX,1
- ADD DI,ES:[OFFSET BACKTab + BX] {use it as write plane }
- MOV StartAdr,DI
- MOV actualAdr,DI
-
- MOV DX,hoehe
- MOV DI,actualAdr
- MOV ES,SegmAdr
-
- {DS:SI = pointer to data, ES:DI = dest. address on screen for them }
- {AL = startplane}
- MOV BX,breite
- ADD BX,3
- SHR BX,1
- SHR BX,1
- mov cx,bx
- @L1:
- push si
- SHR CX,1 {faster than "REP MOVSB" }
- REP MOVSW
- ADC CX,CX
- REP MOVSB
- pop si
- mov cx,bx
- add si,breite1
- MOV DI,actualAdr
- ADD DI,LINESIZE
- MOV actualAdr,DI
- DEC DX
- JNE @L1
-
-
- INC AL {select next bitplane; if wrap-around occurs }
- ADD StartAdr,PAGESIZE {from bitplane 3 to bitplane 0, then the start-}
- AND AL,3 {ing address must be incremented by 1 byte }
- JNE @nowrap1
- SUB StartAdr,4*PAGESIZE-1
- @nowrap1:
- MOV SI,pl_adr2
- MOV DI,StartAdr
- MOV actualAdr,DI
- MOV DX,hoehe
- MOV BX,breite
- INC BX
- INC BX
- SHR BX,1
- SHR BX,1
- mov cx,bx
- @L2:
- push si
- SHR CX,1 {faster than "REP MOVSB" }
- REP MOVSW
- ADC CX,CX
- REP MOVSB
- pop si
- mov cx,bx
- add si,breite2
- MOV DI,actualAdr
- ADD DI,LINESIZE
- MOV actualAdr,DI
- DEC DX
- JNE @L2
-
-
- INC AL {select next bitplane; if wrap-around occurs }
- ADD StartAdr,PAGESIZE {from bitplane 3 to bitplane 0, then the start-}
- AND AL,3 {ing address must be incremented by 1 byte }
- JNE @nowrap2
- SUB StartAdr,4*PAGESIZE-1
- @nowrap2:
- MOV SI,pl_adr3
- MOV DI,StartAdr
- MOV actualAdr,DI
- MOV DX,hoehe
- MOV BX,breite
- INC BX
- SHR BX,1
- SHR BX,1
- mov cx,bx
- @L3:
- push si
- SHR CX,1 {faster than "REP MOVSB" }
- REP MOVSW
- ADC CX,CX
- REP MOVSB
- pop si
- mov cx,bx
- add si,breite3
- MOV DI,actualAdr
- ADD DI,LINESIZE
- MOV actualAdr,DI
- DEC DX
- JNE @L3
-
-
- INC AL {select next bitplane; if wrap-around occurs }
- ADD StartAdr,PAGESIZE {from bitplane 3 to bitplane 0, then the start-}
- AND AL,3 {ing address must be incremented by 1 byte }
- JNE @nowrap3
- SUB StartAdr,4*PAGESIZE-1
- @nowrap3:
- MOV SI,pl_adr4
- MOV DI,StartAdr
- MOV actualAdr,DI
- MOV DX,hoehe
- MOV BX,breite
- SHR BX,1
- SHR BX,1
- mov cx,bx
- @L4:
- push si
- SHR CX,1 {faster than "REP MOVSB" }
- REP MOVSW
- ADC CX,CX
- REP MOVSB
- pop si
- mov cx,bx
- add si,breite4
- MOV DI,actualAdr
- ADD DI,LINESIZE
- MOV actualAdr,DI
- DEC DX
- JNE @L4
-
- MOV AX,SEG @DATA
- MOV DS,AX
- END
- END;
- END;
-
- PROCEDURE FreeImageMem(p:POINTER);
- { in: p = pointer to image memory, allocated by GetImage()}
- {out: - }
- {rem: the heap memory allocated for the image has been released }
- BEGIN
- IF p<>NIL THEN FreeMem(p,MEMW[Seg(p^):Ofs(p^)]*MEMW[Seg(p^):Ofs(p^)+2] + 2*2)
- END;
-
- PROCEDURE Screen(pa:WORD);
- { in: pa = screen page to display (0..1) }
- {out: - }
- {rem: The display has been switched to graphic page pa }
- { The routine does NOT synchronize on any retrace-signal }
- { Sensible page values are only 0 or 1 here, but the routine }
- { doesn't make any checks!}
- BEGIN
- ASM
- MOV DX,CRTAddress {CRT-Controller}
- MOV AL,$0D {LB-startaddress-register}
- CLI {May not be interrupted! }
- OUT DX,AL
- INC DX
- {realize "AX := Offset_Adr[pa]": }
- MOV BX,pa
- MOV SI,BX
- AND SI,3 {page value *2 (word-sized entries!)}
- SHL SI,1 {add start address of array to that }
- ADD SI,OFFSET Offset_Adr-StartIndex*2 {evtl. correct displacement }
- LODSW {and fetch value}
- OUT DX,AL {set LB of new starting address }
- DEC DX
- MOV AL,$0C
- OUT DX,AL
- INC DX
- MOV AL,AH {set HB of new starting address }
- OUT DX,AL
- STI
- END;
- END;
-
- PROCEDURE InitGraph;
- { in: PAGE = actual graphic page }
- {out: - }
- {rem: switches the VGA-card into 320x200x256x4-mode; ATTENTION! }
- { This mode is different from mode $13 of the VGA-BIOS!!! }
- { The display will be switched to graphic page 1-PAGE }
- { The default colors of mode $13 will be set! }
- BEGIN
- ASM
- MOV AX,0013h {use BIOS to set graphic mode $13 (320x200x256) }
- INT 10h
- MOV DX,03C4h {select memory-mode-register at sequencer port }
- MOV AL,04
- OUT DX,AL
- INC DX {read in data via the according data register }
- IN AL,DX
- AND AL,0F7h {bit 3 := 0: don't chain the 4 planes}
- OR AL,04 {bit 2 := 1: no odd/even mechanism }
- OUT DX,AL {activate new settings }
- MOV DX,03C4h {s.a.: address sequencer reg. 2 (=map-mask),... }
- MOV AL,02
- OUT DX,AL
- INC DX
- MOV AL,0Fh {...and allow access to all 4 bit maps }
- OUT DX,AL
- MOV AX,0A000h {starting with segment A000h, set 8000h logical }
- MOV ES,AX {words = 4*8000h physical words (because of 4 }
- SUB DI,DI {bitplanes) to 0 }
- MOV AX,DI
- MOV CX,8000h
- CLD
- REP STOSW
-
- MOV DX,CRTAddress {address the underline-location-register at }
- MOV AL,14h {the CRT-controller port, read out the according }
- OUT DX,AL {data register: }
- INC DX
- IN AL,DX
- AND AL,0BFh {bit 6:=0: no double word addressing scheme in}
- OUT DX,AL {video RAM }
- DEC DX
- MOV AL,17h {select mode control register }
- OUT DX,AL
- INC DX
- IN AL,DX
- OR AL,40h {bit 6 := 1: memory access scheme=linear bit array }
- OUT DX,AL
- END;
- Screen(1-PAGE); {ALWAYS is the non-actual graphic page the visible one!}
- SetPalette(DefaultColors,FALSE) {set default palette, just to be sure! }
- END;
-
-
- VAR d,dp,dq,WindowY2:INTEGER;
- PROCEDURE BackgroundLine(x1,y1,x2,y2:INTEGER);
- { in: x1,y1,x2,y2 = coordinates of two points, }
- { Color = color (0..255) }
- { StartVirtualX,StartVirtualY = upper left image corner }
- { WinClip = TRUE, if line shall be clipped to the window area }
- { WinXMIN,WinXMAX,WinYMIN,WinYMAX = window for evtl. clipping }
- {out: - }
- {rem: A line has been drawn between the VIRTUAL points (x1,y1) and (x2,y2) }
- { using the color COLOR; the routine will take care of transforming }
- { the coordinates to absolute screen coordinates and evtl. necessary }
- { clipping actions. }
- { The line will NOT automatically be taken over into the background }
- { image, that is: it will be visible only for one animation cycle (if }
- { it shall stay permanent, you have to draw it into the background!) }
- { (For that reason, you should call this routine AFTER calling ANIMATE }
- { because otherwise, the drawn line will vanish at once!) }
- CONST CodeLinks =$7; {%0111}
- CodeRechts=$B; {%1011}
- CodeOben =$D; {%1101}
- CodeUnten =$E; {%1110}
- BEGIN
- IF EMSused
- THEN EMSFillFrame(BackgroundEMSHandle); {prepare EMS access }
-
- {first clip line to visible window; use Sutherland-Cohen-algorithm: }
- {use 4 bit-codes for: left|right|top|bottom }
- ASM
- CLD
- XOR BX,BX
- MOV SI,XMAX
- XOR DI,DI
- MOV AX,YMAX
- CMP WinClip,FALSE
- JE @Start
- MOV BX,WinXMIN
- MOV SI,WinXMAX
- MOV DI,WinYMIN
- MOV AX,WinYMAX
- @Start:
- MOV WindowY2,AX
- {BX|SI|DI|WindowY2 = WinXMIN|WinXMAX|WinYMIN|WinYMAX or 0|XMAX|0|YMAX }
-
- MOV CL,$F {start with %1111 }
- MOV AX,x2
- SUB AX,StartVirtualX {transform x2 into absolute coordinates}
- MOV x2,AX
- CMP AX,BX {x2 < WindowX1 ?}
- JL @GC1Punkt2 {yes, don't change flag for "point is left of window"}
- AND CL,CodeLinks {no, reset flag }
- @GC1Punkt2:
- CMP AX,SI {x2 > WindowX2 ?}
- JG @GC2Punkt2 {yes, don't change flag for "point is right of window"}
- AND CL,CodeRechts {no, reset flag }
- @GC2Punkt2:
- MOV AX,y2
- SUB AX,StartVirtualY {transform y2 into absolute coordinates}
- MOV y2,AX
- CMP AX,DI {y2 < WindowY1 ?}
- JL @GC3Punkt2 {yes, don't change flag for "point is above window"}
- AND CL,CodeOben {no, reset flag }
- @GC3Punkt2:
- CMP AX,WindowY2 {y2 > WindowY2 ?}
- JG @GC4Punkt2 {yes, don't change flag for "point is below window"}
- AND CL,CodeUnten
- @GC4Punkt2: {CL holds the area code for point 2 }
-
- MOV AX,x1
- SUB AX,StartVirtualX {transform x1 into absolute coordinates}
- MOV x1,AX
- MOV AX,y1
- SUB AX,StartVirtualY {transform y1 into absolute coordinates}
- MOV y1,AX
-
- @Punkt1:
- MOV CH,$F {start with %1111 }
- MOV AX,x1
- CMP AX,BX {x1 < WindowX1 ?}
- JL @GC1Punkt1 {yes, don't change flag for "point is left of window"}
- AND CH,CodeLinks {no, reset flag }
- @GC1Punkt1:
- CMP AX,SI {x1 > WindowX2 ?}
- JG @GC2Punkt1 {yes, don't change flag for "point is right of window"}
- AND CH,CodeRechts {no, reset flag }
- @GC2Punkt1:
- MOV AX,y1
- CMP AX,DI {y1 < WindowY1 ?}
- JL @GC3Punkt1 {yes, don't change flag for "point is above window"}
- AND CH,CodeOben {no, reset flag }
- @GC3Punkt1:
- CMP AX,WindowY2 {y1 > WindowY2 ?}
- JG @GC4Punkt1 {yes, don't change flag for "point is below window"}
- AND CH,CodeUnten
- @GC4Punkt1: {CH holds the area code for point 1 }
-
- {CL holds the area code for point 2, CH the one for point 1}
-
- MOV AX,CX
- AND AL,AH {Code1 AND Code2 <> 0 ?}
- JNZ @LineReady {yes, line is completely outside the window}
- MOV AX,CX
- OR AL,AH {Code1 OR Code2 = 0 ?}
- JZ @DrawLine {yes, line is completely inside the window}
-
- {Now do the clipping itself: }
- MOV AX,CX
- OR AH,AH {Code1 =0 ?}
- JNZ @CL3 {no, everything ok}
- MOV AX,x1 {yes, swap points! }
- XCHG AX,x2
- MOV x1,AX
- MOV AX,y1
- XCHG AX,y2
- MOV y1,AX
- XCHG CL,CH
- @CL3:
- MOV AX,x2
- SUB AX,x1
- MOV dp,AX {dp := x2 - x1}
- MOV AX,y2
- SUB AX,y1
- MOV dq,AX {dq := y2 - y1}
-
- MOV AL,CH {AL := Code1}
- TEST AL,NOT CodeLinks {point1 left of window? }
- JZ @CL4 {no }
- {yes, compute new coordinates: }
- { y1 := y1 + (y2 - y1) / (x2 - x1) * (WindowX1 - X1) }
- { and x1 := WindowX1}
- MOV AX,BX
- SUB AX,x1 {AX := WindowX1-x1}
- IMUL dq
- IDIV dp
- ADD y1,AX
- MOV x1,BX
- JMP @Punkt1
-
- @CL4:
- TEST AL,NOT CodeRechts {point1 right of window? }
- JZ @CL5 {no }
- {yes, compute:}
- { y1 := y1 + (y2 - y1) / (x2 - x1) * (WindowX2 - X1), x1 := WindowX2}
- MOV AX,SI {SI = WindowX2}
- SUB AX,x1
- IMUL dq
- IDIV dp
- ADD y1,AX
- MOV x1,SI
- JMP @Punkt1
-
- @CL5:
- TEST AL,NOT CodeOben {point1 above window? }
- JZ @CL6 {no }
- {yes, compute:}
- { x1 := x1 + (x2 - x1) / (y2 - y1) * (WindowY1 - y1), y1 := WindowY1 }
- MOV AX,DI {DI = WindowY1}
- SUB AX,y1
- IMUL dp
- IDIV dq
- ADD x1,AX
- MOV y1,DI
- JMP @Punkt1
-
- @CL6:
- TEST AL,NOT CodeUnten {point below window? }
- JZ @Punkt1 {no }
- {yes, compute:}
- { x1 := x1 + (x2 - x1) / (y2 - y1) * (WindowY2 - y1), y1 := WindowY2 }
- MOV AX,WindowY2
- PUSH AX
- SUB AX,y1
- IMUL dp
- IDIV dq
- ADD x1,AX
- POP AX
- MOV y1,AX
- JMP @Punkt1
-
- {precondition here: both points have been clipped to the visible window;}
- {if the line is completely offscreen, the program jumped directly to }
- {@LineReady, instead! }
- @DrawLine:
- MOV DX,x1
- SUB DX,x2
- JGE @posdx
- NEG DX
- @posdx:
- MOV AX,y1
- SUB AX,y2
- JGE @posdy
- NEG AX
- @posdy:
- {AX = new deltaY, DX = new deltaX }
- XOR CX,CX
- CMP AX,DX
- JBE @noswap1
- XCHG AX,DX
- INC CX
- @noswap1:
- {AX = deltaY, DX = deltaX (if CX=0), AX = deltaX, DX = deltaY (if CX=1) }
- SHL AX,1
- MOV dp,AX
- SUB AX,DX
- MOV d,AX
- SUB AX,DX
- MOV dq,AX
-
- JCXZ @then
- JMP @else
-
- @then:
- MOV CX,x2
- MOV AX,x1
- MOV DX,y1
- MOV BX,y2
- CMP AX,CX
- JBE @noswap2
- XCHG AX,CX
- XCHG DX,BX
- @noswap2:
- {AX = new X1, CX = new X2, DX = new Y1, BX = new Y2 }
- SUB CX,AX
- INC CX {CX := x2 - x1 + 1 }
- MOV SI,LINESIZE
- CMP DX,BX
- JBE @okay1
- NEG SI
- @okay1:
- {SI = ±LINESIZE, CX = #pixel, AX = X1, DX = Y1}
- MOV DI,DX
- SHL DI,1
- MOV DI,CS:[OFFSET gadr + DI] {DI := y1 * LINESIZE}
- MOV BL,AL
- SHR AX,1
- SHR AX,1
- ADD DI,AX {DI := y1 * LINESIZE + (x1 DIV 4) }
-
- AND BX,3 {BX := (x1 AND 4) }
- SHL BX,1 {*2, because word-sized}
- ADD DI,[OFFSET BACKTab + BX] {get mask for access: BX * 16000 }
-
- MOV BL,BACKGNDPAGE {BH = 0 -> BX = drawing page}
- SHL BX,1
- MOV ES,[BX + OFFSET Segment_Adr -StartIndex*2] {ES:DI=pointer to 1.pixel}
-
- MOV AL,Color
- MOV DX,d
- MOV BX,dq
-
- @loop1:
- MOV ES:[DI],AL
- ADD DI,PAGESIZE
- JC @wrap1
- CMP DI,4*PAGESIZE
- JB @nowrap1
- @wrap1:
- SUB DI,4*PAGESIZE-1 {back in plane0, but 1 byte down }
- @nowrap1: {AL = color, SI = ±LINESIZE, ES:DI=pointer to 1.pixel}
- {BX = dq, DX = d}
- OR DX,DX
- JGE @newline
- ADD DX,dp
- LOOP @loop1
- JMP @raus
-
- @newline:
- ADD DI,SI
- ADD DX,BX
- LOOP @loop1
- JMP @raus
-
-
- @else:
- MOV CX,y2
- MOV AX,y1
- MOV DX,x1
- MOV BX,x2
- CMP AX,CX
- JBE @noswap3
- XCHG AX,CX
- XCHG DX,BX
- @noswap3:
- {AX = new Y1, BX = new X2, CX = new Y2, DX = new X1 }
- SUB CX,AX
- INC CX
- MOV SI,PAGESIZE
- CMP DX,BX
- JBE @okay2
- NEG SI
- @okay2:
- {SI = ±PAGESIZE, CX = #pixel, DX = X1, AX = Y1}
- MOV DI,AX
- SHL DI,1
- MOV DI,CS:[OFFSET gadr + DI] {DI := y1 * LINESIZE}
- MOV BL,DL
- SHR DX,1
- SHR DX,1
- ADD DI,DX {DI := y1 * LINESIZE + (x1 DIV 4) }
-
- AND BX,3 {BX := (x1 AND 4) }
- SHL BX,1 {*2, because word-sized}
- ADD DI,[OFFSET BACKTab + BX] {get mask for access: BX * 16000 }
-
- MOV BL,BACKGNDPAGE {BH = 0 -> BX = drawing page}
- SHL BX,1
- MOV ES,[BX + OFFSET Segment_Adr -StartIndex*2] {ES:DI=pointer to 1.pixel}
-
- MOV AL,Color
- MOV DX,d
- MOV BX,dq
-
- @loop2:
- MOV ES:[DI],AL
- ADD DI,LINESIZE
- OR DX,DX
- JGE @newcolumn
- ADD DX,dp
- LOOP @loop2
- JMP @raus
-
- @newcolumn:
- OR SI,SI
- JGE @plus
- {increment SI<0, check for underflow: }
- ADD DI,SI
- JC @nowrap2
- ADD DI,4*PAGESIZE-1
- JMP @nowrap2
- @plus:
- {increment SI>0, check vor overflow & >= 4*PAGESIZE }
- ADD DI,SI
- JC @wrap2
- CMP DI,4*PAGESIZE
- JB @nowrap2
- @wrap2:
- SUB DI,4*PAGESIZE-1
- @nowrap2:
- ADD DX,BX
- LOOP @loop2
- JMP @raus
-
- @raus:
- @LineReady:
- END;
- END;
-
- PROCEDURE Line(x1,y1,x2,y2:INTEGER; pa:WORD);
- { in: x1,y1,x2,y2 = coordinates of two points, }
- { Color = color (0..255) }
- { StartVirtualX,StartVirtualY = upper left image corner }
- { pa = graphic page to be drawn upon (0..3) }
- { WinClip = TRUE, if line shall be clipped to the window area }
- { WinXMIN,WinXMAX,WinYMIN,WinYMAX = window for evtl. clipping }
- {out: - }
- {rem: A line has been drawn between the VIRTUAL points (x1,y1) and (x2,y2) }
- { using the color COLOR; the routine will take care of transforming }
- { the coordinates to absolute screen coordinates and evtl. necessary }
- { clipping actions. }
- { The line will NOT automatically be taken over into the background }
- { image, that is: it will be visible only for one animation cycle (if }
- { it shall stay permanent, you have to draw it into the background!) }
- { (For that reason, you should call this routine AFTER calling ANIMATE }
- { because otherwise, the drawn line will vanish at once!) }
- CONST CodeLinks =$7; {%0111}
- CodeRechts=$B; {%1011}
- CodeOben =$D; {%1101}
- CodeUnten =$E; {%1110}
- BEGIN
- IF (pa<0) OR (pa>SCROLLPAGE)
- THEN Error:=Err_InvalidPageNumber
- ELSE IF pa=BACKGNDPAGE
- THEN BackgroundLine(x1,y1,x2,y2)
- ELSE
- {first clip line to visible window; use Sutherland-Cohen-algorithm: }
- {use 4 bit-codes for: left|right|top|bottom }
- ASM
- CLD
- XOR BX,BX
- MOV SI,XMAX
- XOR DI,DI
- MOV AX,YMAX
- CMP WinClip,FALSE
- JE @Start
- MOV BX,WinXMIN
- MOV SI,WinXMAX
- MOV DI,WinYMIN
- MOV AX,WinYMAX
- @Start:
- MOV WindowY2,AX
- {BX|SI|DI|WindowY2 = WinXMIN|WinXMAX|WinYMIN|WinYMAX or 0|XMAX|0|YMAX }
-
- MOV CL,$F {start with %1111 }
- MOV AX,x2
- SUB AX,StartVirtualX {transform x2 into absolute coordinates}
- MOV x2,AX
- CMP AX,BX {x2 < WindowX1 ?}
- JL @GC1Punkt2 {yes, don't change flag for "point is left of window"}
- AND CL,CodeLinks {no, reset flag }
- @GC1Punkt2:
- CMP AX,SI {x2 > WindowX2 ?}
- JG @GC2Punkt2 {yes, don't change flag for "point is right of window"}
- AND CL,CodeRechts {no, reset flag }
- @GC2Punkt2:
- MOV AX,y2
- SUB AX,StartVirtualY {transform y2 into absolute coordinates}
- MOV y2,AX
- CMP AX,DI {y2 < WindowY1 ?}
- JL @GC3Punkt2 {yes, don't change flag for "point is above window"}
- AND CL,CodeOben {no, reset flag }
- @GC3Punkt2:
- CMP AX,WindowY2 {y2 > WindowY2 ?}
- JG @GC4Punkt2 {yes, don't change flag for "point is below window"}
- AND CL,CodeUnten
- @GC4Punkt2: {CL holds the area code for point 2 }
-
- MOV AX,x1
- SUB AX,StartVirtualX {transform x1 into absolute coordinates}
- MOV x1,AX
- MOV AX,y1
- SUB AX,StartVirtualY {transform y1 into absolute coordinates}
- MOV y1,AX
-
- @Punkt1:
- MOV CH,$F {start with %1111 }
- MOV AX,x1
- CMP AX,BX {x1 < WindowX1 ?}
- JL @GC1Punkt1 {yes, don't change flag for "point is left of window"}
- AND CH,CodeLinks {no, reset flag }
- @GC1Punkt1:
- CMP AX,SI {x1 > WindowX2 ?}
- JG @GC2Punkt1 {yes, don't change flag for "point is right of window"}
- AND CH,CodeRechts {no, reset flag }
- @GC2Punkt1:
- MOV AX,y1
- CMP AX,DI {y1 < WindowY1 ?}
- JL @GC3Punkt1 {yes, don't change flag for "point is above window"}
- AND CH,CodeOben {no, reset flag }
- @GC3Punkt1:
- CMP AX,WindowY2 {y1 > WindowY2 ?}
- JG @GC4Punkt1 {yes, don't change flag for "point is below window"}
- AND CH,CodeUnten
- @GC4Punkt1: {CH holds the area code for point 1 }
-
- {CL holds the area code for point 2, CH the one for point 1}
-
- MOV AX,CX
- AND AL,AH {Code1 AND Code2 <> 0 ?}
- JNZ @LineReady {yes, line is completely outside the window}
- MOV AX,CX
- OR AL,AH {Code1 OR Code2 = 0 ?}
- JZ @DrawLine {yes, line is completely inside the window}
-
- {Now do the clipping itself: }
- MOV AX,CX
- OR AH,AH {Code1 =0 ?}
- JNZ @CL3 {no, everything ok}
- MOV AX,x1 {yes, swap points! }
- XCHG AX,x2
- MOV x1,AX
- MOV AX,y1
- XCHG AX,y2
- MOV y1,AX
- XCHG CL,CH
- @CL3:
- MOV AX,x2
- SUB AX,x1
- MOV dp,AX {dp := x2 - x1}
- MOV AX,y2
- SUB AX,y1
- MOV dq,AX {dq := y2 - y1}
-
- MOV AL,CH {AL := Code1}
- TEST AL,NOT CodeLinks {point1 left of window? }
- JZ @CL4 {no }
- {yes, compute new coordinates: }
- { y1 := y1 + (y2 - y1) / (x2 - x1) * (WindowX1 - X1) }
- { and x1 := WindowX1}
- MOV AX,BX
- SUB AX,x1 {AX := WindowX1-x1}
- IMUL dq
- IDIV dp
- ADD y1,AX
- MOV x1,BX
- JMP @Punkt1
-
- @CL4:
- TEST AL,NOT CodeRechts {point1 right of window? }
- JZ @CL5 {no }
- {yes, compute:}
- { y1 := y1 + (y2 - y1) / (x2 - x1) * (WindowX2 - X1), x1 := WindowX2}
- MOV AX,SI {SI = WindowX2}
- SUB AX,x1
- IMUL dq
- IDIV dp
- ADD y1,AX
- MOV x1,SI
- JMP @Punkt1
-
- @CL5:
- TEST AL,NOT CodeOben {point1 above window? }
- JZ @CL6 {no }
- {yes, compute:}
- { x1 := x1 + (x2 - x1) / (y2 - y1) * (WindowY1 - y1), y1 := WindowY1 }
- MOV AX,DI {DI = WindowY1}
- SUB AX,y1
- IMUL dp
- IDIV dq
- ADD x1,AX
- MOV y1,DI
- JMP @Punkt1
-
- @CL6:
- TEST AL,NOT CodeUnten {point below window? }
- JZ @Punkt1 {no }
- {yes, compute:}
- { x1 := x1 + (x2 - x1) / (y2 - y1) * (WindowY2 - y1), y1 := WindowY2 }
- MOV AX,WindowY2
- PUSH AX
- SUB AX,y1
- IMUL dp
- IDIV dq
- ADD x1,AX
- POP AX
- MOV y1,AX
- JMP @Punkt1
-
- {precondition here: both points have been clipped to the visible window;}
- {if the line is completely offscreen, the program jumped directly to }
- {@LineReady, instead! }
- @DrawLine:
- PUSH BP
- MOV Steigung,0 {reset Flag }
- MOV CX,x2
- SUB CX,x1 {point1 right of point2 ? }
- JGE @posDX {no }
- NEG CX {yes, swap points }
- MOV AX,x1
- XCHG AX,x2
- MOV x1,AX
- MOV AX,y1
- XCHG AX,y2
- MOV y1,AX
-
- @posDX:
- MOV DI,y1
- SHL DI,1
- MOV DI,CS:[OFFSET gadr + DI] {DI := y1 * LINESIZE}
- MOV AX,x1
- MOV BL,AL
- SHR AX,1
- SHR AX,1
- ADD DI,AX {DI := y1 * LINESIZE + (x1 DIV 4) }
-
- AND BX,3 {BX := (x1 AND 4) }
- MOV DH,[OFFSET TranslateTab + BX] {get mask for VRAM-access }
- MOV DL,2
-
- MOV BX,pa {BX = drawing page}
- SHL BX,1
- MOV ES,[BX +OFFSET Segment_Adr -StartIndex*2]
-
- {ES:DI=pointer to graphic address of point1, DX=access mask for it}
- MOV SI,LINESIZE
- MOV BX,y2
- SUB BX,y1 {point1 below point2 ? }
- JG @posDY {no }
- NEG BX {yes, negate deltaY and row-increment }
- NEG SI
-
- @posDY:
- CMP BX,CX {deltaY > deltaX ?}
- JLE @flach {no: small slope, <=1 }
- XCHG BX,CX {yes, swap deltas and set flag }
- MOV Steigung,1
-
- {compute Bresenham-parameters: 2 * DY, 2 * DY - DX, 2 * (DY - DX) }
- @flach:
- SHL BX,1
- MOV DY_mal2,BX
- SUB BX,CX
- MOV BP,BX {BP := 2 * DY - DX}
- SUB BX,CX
- MOV DY_m_DX_mal2,BX
- INC CX {CX := number of pixels}
- MOV BL,Color
- MOV BH,1
- CMP Steigung,0 {steep line? }
- JNZ @high1 {yes}
-
- @low1: {no }
- MOV AX,3C4h
- XCHG AX,DX
- OUT DX,AX {select correct bitplane }
- MOV DX,AX {save mask to DX again }
- MOV AL,BL {get color of point }
- STOSB {draw point }
- SHL DH,1 {compute mask for next point }
- CMP DH,16 {still addressable with the same address?}
- JE @nextbyte1 {no, address had to be incremented by 1 }
- DEC DI {yes, make incrementing DI undone }
- @low1b:
- OR BP,BP
- JGE @low2
- ADD BP,DY_mal2
- LOOP @low1
- JMP @raus
- @nextbyte1:
- MOV DH,BH {restore mask to 1 }
- JMP @low1b {rest as above }
-
- @low2:
- ADD BP,DY_m_DX_mal2
- ADD DI,SI
- LOOP @low1
- JMP @raus
-
-
- @high1:
- MOV AX,3C4h
- XCHG AX,DX
- OUT DX,AX
- MOV DX,AX
- MOV AL,BL
- @high1b:
- OR BP,BP
- JGE @high2
- ADD BP,DY_mal2
- MOV ES:[DI],AL
- ADD DI,SI
- LOOP @high1b
- JMP @raus
-
- @high2:
- ADD BP,DY_m_DX_mal2
- SHL DH,1
- CMP DH,16
- JE @nextbyte2
- MOV ES:[DI],AL
- ADD DI,SI
- LOOP @high1
- JMP @raus
- @nextbyte2:
- MOV DH,BH
- STOSB
- ADD DI,SI
- LOOP @high1
-
- @raus:
- POP BP
- @LineReady:
- END;
- END;
-
- FUNCTION GetPixel(x,y:INTEGER):BYTE; ASSEMBLER;
- { in: x,y = VIRTUAL pixel coordinates of the point to be read }
- { PAGEADR= graphic page(segment) to be read from }
- { StartVirtualX, StartVirtualY = upper left image corner }
- {out: color of the point}
- {rem: If the pixel lies outside the visible window, the routine }
- { will return "0" as the result }
- { Attention! As PAGEADR always specifies the NOT visible gra- }
- { phic page, this routine will read from there, too! }
- ASM
- XOR AL,AL {preset AL with 0 }
- MOV DI,y
- SUB DI,StartVirtualY {transform y into absolute coordinates}
- JS @offscrn
- CMP DI,YMAX
- JG @offscrn
- MOV BX,x
- SUB BX,StartVirtualX {transform x into absolute coordinates}
- JS @offscrn
- CMP BX,XMAX
- JG @offscrn
- SHL DI,1
- MOV DI,CS:[OFFSET gadr + DI]
- {DI = Y * LINESIZE, BX = X, coordinates admissible}
- MOV AX,BX
- SHR AX,1
- SHR AX,1
- ADD DI,AX {DI = Y * LINESIZE + (X SHR 2) }
- AND BL,3 {BL = X MOD 4 = plane to read from}
- MOV AL,4
- MOV AH,BL
- MOV DX,3CEh
-
- MOV ES,PAGEADR
- CLI
- OUT DX,AX
- MOV AL,ES:[DI]
- STI
- @offscrn:
- END;
-
-
- FUNCTION BackgroundGetPixel(x,y:INTEGER):BYTE; ASSEMBLER;
- { in: x,y = VIRTUAL pixel coordinates of the point to be read }
- { StartVirtualX, StartVirtualY = upper left image corner }
- {out: color of the point in the background page}
- {rem: If the pixel lies outside the visible window, the routine }
- { will return "0" as the result }
- { Because BACKGNDADR is used as background page, calling }
- { this routine only makes sense when using mode STATIC! }
- { If EMS is used then the calling routine must take care }
- { that the EMS page frame contains the proper data (which can }
- { be done by the statement "IF EMSused THEN EnsureEMSConsistency()")}
- ASM
- XOR AL,AL {preset AL with 0 }
- MOV DI,y
- SUB DI,StartVirtualY {transform y into absolute coordinates}
- JS @offscrn
- CMP DI,YMAX
- JG @offscrn
- MOV BX,x
- SUB BX,StartVirtualX {transform x into absolute coordinates}
- JS @offscrn
- CMP BX,XMAX
- JG @offscrn
- SHL DI,1
- MOV DI,CS:[OFFSET gadr + DI]
- {DI = Y * LINESIZE, BX = X, coordinates admissible}
- MOV AX,BX
- SHR AX,1
- SHR AX,1
- ADD DI,AX {DI = Y * LINESIZE + (X SHR 2) }
- AND BX,3 {BX := (x1 AND 4) }
- SHL BX,1 {*2, because word-sized}
- ADD DI,[OFFSET BACKTab + BX] {get mask for access: BX * 16000 }
- MOV ES,BACKGNDADR
- MOV AL,ES:[DI]
- @offscrn:
- END;
-
- FUNCTION PageGetPixel(x,y:INTEGER; pa:WORD):BYTE; ASSEMBLER;
- { in: x,y = VIRTUAL pixel coordinates of the point to be read }
- { pa = graphic page (0..3), from which the point shall be }
- { read out }
- { StartVirtualX, StartVirtualY = upper left image corner }
- {out: color of the point in the background page}
- {rem: If the pixel lies outside the visible window, the routine }
- { will return "0" as the result }
- { If you want to read from the actually VISIBLE page, then }
- { then you must call the routine with pa=1-PAGE! }
- { Sensible values for "pa" are either 0 or 1 (and evtl. BACK- }
- { GNDPAGE, if you are using background mode STATIC), however, }
- { the routine doesn't check that! }
- ASM
- CMP pa,BACKGNDPAGE
- JNE @doit
- PUSH x
- PUSH y
- CALL BackgroundGetPixel
- JMP @offscrn
-
- @doit:
- XOR AL,AL {preset AL with 0 }
- MOV DI,y
- SUB DI,StartVirtualY {transform y into absolute coordinates}
- JS @offscrn
- CMP DI,YMAX
- JG @offscrn
- MOV BX,x
- SUB BX,StartVirtualX {transform x into absolute coordinates}
- JS @offscrn
- CMP BX,XMAX
- JG @offscrn
- SHL DI,1
- MOV DI,CS:[OFFSET gadr + DI]
- {DI = Y * LINESIZE, BX = X, coordinates admissible}
- MOV AX,BX
- SHR AX,1
- SHR AX,1
- ADD DI,AX {DI = Y * LINESIZE + (X SHR 2) }
- AND BX,3 {BL = X MOD 4 = plane to read from; BH = 0}
- MOV AL,4
- MOV AH,BL
- MOV BX,pa {BX = graphic page}
- AND BX,3 {only pages 0..3}
- SHL BX,1
- MOV ES,[BX +OFFSET Segment_Adr-StartIndex*2]
-
- CLI
- MOV DX,3CEh
- OUT DX,AX
- MOV AL,ES:[DI]
- STI
- @offscrn:
- END;
-
-
- PROCEDURE PutPixel(x,y:INTEGER; color:Byte); ASSEMBLER;
- { in: x,y = VIRTUAL pixel coordinates of the point to be written }
- { color = color value for the pixel to be drawn}
- { 1-PAGE = graphic page to be drawn upon }
- { StartVirtualX, StartVirtualY = upper left image corner }
- { WinClip= TRUE, if line shall be clipped to the window area }
- { WinXMIN,WinXMAX,WinYMIN,WinYMAX = window for evtl. clipping }
- {out: - }
- {rem: The point (x,y) has been transformed to absolute screen coordinates }
- { and has been drawn (if it lies within the visible window) }
- { The pixel will NOT automatically be overtaken into the background }
- { image, that is: it will be visible only for one animation cycle! }
- { (For that reason, you should call this routine AFTER calling ANIMATE }
- { because otherwise, the drawn point will vanish at once!) }
- ASM
- CMP WinClip,TRUE
- JE @goClip
-
- MOV DI,y
- SUB DI,StartVirtualY {transform y into absolute coordinates}
- JS @offscrn
- CMP DI,YMAX
- JG @offscrn
- MOV BX,x
- SUB BX,StartVirtualX {transform x into absolute coordinates}
- JS @offscrn
- CMP BX,XMAX
- JG @offscrn
- SHL DI,1
- MOV DI,CS:[OFFSET gadr + DI]
- {DI = Y * LINESIZE, BX = X, coordinates admissible}
- MOV AX,BX
- SHR AX,1
- SHR AX,1
- ADD DI,AX {DI = Y * LINESIZE + (X SHR 2) }
- AND BX,3
- MOV AH,[OFFSET TranslateTab + BX]
- MOV AL,2
- MOV DX,3C4h
-
- MOV BX,1 {ES := Segment_Adr[1-PAGE], because 1-PAGE = visible page}
- SUB BX,PAGE
- SHL BX,1
- MOV ES,[BX +OFFSET Segment_Adr-StartIndex*2]
-
- CLI
- OUT DX,AX
- MOV AL,color
- MOV ES:[DI],AL {faster than STOSB on >=386!}
- STI
- JMP @ende
-
- @goClip: {to this address, if clipping active}
- MOV DI,y
- SUB DI,StartVirtualY {transform y into absolute coordinates}
- CMP DI,WinYMIN
- JL @offscrn
- CMP DI,WinYMAX
- JG @offscrn
- MOV BX,x
- SUB BX,StartVirtualX {transform x into absolute coordinates}
- CMP BX,WinXMIN
- JL @offscrn
- CMP BX,WinXMAX
- JG @offscrn
- SHL DI,1
- MOV DI,CS:[OFFSET gadr + DI]
- {DI = Y * LINESIZE, BX = X, coordinates admissible}
- MOV AX,BX
- SHR AX,1
- SHR AX,1
- ADD DI,AX {DI = Y * LINESIZE + (X SHR 2) }
- AND BX,3
- MOV AH,[OFFSET TranslateTab + BX]
- MOV AL,2
- MOV DX,3C4h
-
- MOV BX,1 {ES := Segment_Adr[1-PAGE], because 1-PAGE = visible page}
- SUB BX,PAGE
- SHL BX,1
- MOV ES,[BX +OFFSET Segment_Adr-StartIndex*2]
-
- CLI
- OUT DX,AX
- MOV AL,color
- MOV ES:[DI],AL {faster than STOSB on >=386!}
- STI
- @offscrn:
- @ende:
- END;
-
- PROCEDURE BackgroundPutPixel(x,y:INTEGER; color:Byte); ASSEMBLER;
- { in: x,y = VIRTUAL pixel coordinates of the point to be written }
- { color = color value for the pixel to be drawn}
- { StartVirtualX, StartVirtualY = upper left image corner }
- { WinClip=TRUE, if line shall be clipped to the window area }
- { WinXMIN,WinXMAX,WinYMIN,WinYMAX = window for evtl. clipping }
- {out: - }
- {rem: The point (x,y) has been transformed to absolute screen coordinates and}
- { has been drawn into the background (if it is onscreen) }
- { The pixel will NOT be visible until the next animation cycle takes }
- { place (but then, it remains permanent) (For that reason, you should }
- { call this routine BEFORE calling ANIMATE. That way, evtl. changes to }
- { the background will be visible "at once"!) }
- { Because BACKGNDPAGE is used as background page, calling this }
- { routine only makes sense when using background mode STATIC!}
- { If EMS is used then the calling routine must take care }
- { that the EMS page frame contains the proper data (which can }
- { be done by the statement "IF EMSused THEN EnsureEMSConsistency()")}
- ASM
- CMP WinClip,TRUE
- JE @goClip
-
- MOV DI,y
- SUB DI,StartVirtualY {transform y into absolute coordinates}
- JS @offscrn
- CMP DI,YMAX
- JG @offscrn
- MOV BX,x
- SUB BX,StartVirtualX {transform x into absolute coordinates}
- JS @offscrn
- CMP BX,XMAX
- JG @offscrn
- SHL DI,1
- MOV DI,CS:[OFFSET gadr + DI]
- {DI = Y * LINESIZE, BX = X, coordinates admissible}
- MOV AX,BX
- SHR AX,1
- SHR AX,1
- ADD DI,AX {DI = Y * LINESIZE + (X SHR 2) }
- AND BX,3 {BX := (x1 AND 4) }
- SHL BX,1 {*2, because word-sized}
- ADD DI,[OFFSET BACKTab + BX] {get mask for access: BX * 16000 }
- MOV ES,BACKGNDADR
- MOV AL,color
- MOV ES:[DI],AL {faster than STOSB on >=386!}
- JMP @ende
-
- @goClip: {to this address, if clipping active}
- MOV DI,y
- SUB DI,StartVirtualY {transform y into absolute coordinates}
- CMP DI,WinYMIN
- JL @offscrn
- CMP DI,WinYMAX
- JG @offscrn
- MOV BX,x
- SUB BX,StartVirtualX {transform x into absolute coordinates}
- CMP BX,WinXMIN
- JL @offscrn
- CMP BX,WinXMAX
- JG @offscrn
- SHL DI,1
- MOV DI,CS:[OFFSET gadr + DI]
- {DI = Y * LINESIZE, BX = X, coordinates admissible}
- MOV AX,BX
- SHR AX,1
- SHR AX,1
- ADD DI,AX {DI = Y * LINESIZE + (X SHR 2) }
- AND BX,3 {BX := (x1 AND 4) }
- SHL BX,1 {*2, because word-sized}
- ADD DI,[OFFSET BACKTab + BX] {get mask for access: BX * 16000 }
- MOV ES,BACKGNDADR
- MOV AL,color
- MOV ES:[DI],AL {faster than STOSB on >=386!}
- @offscrn:
- @ende:
- END;
-
- PROCEDURE PagePutPixel(x,y:INTEGER; color:BYTE; pa:WORD); ASSEMBLER;
- { in: x,y = VIRTUAL pixel coordinates of the point to be written }
- { color = color value for the pixel to be drawn}
- { pa = graphic page (0..3) to be drawn upon }
- { PAGEADR= graphic page(segment) to be drawn upon }
- { StartVirtualX, StartVirtualY = upper left image corner }
- { WinClip= TRUE, if line shall be clipped to the window area }
- { WinXMIN,WinXMAX,WinYMIN,WinYMAX = window for evtl. clipping }
- {out: - }
- {rem: The point (x,y) has been transformed to absolute screen coordinates }
- { and has been drawn (if it lies within the visible window) }
- { If you want to draw at the actually VISIBLE graphic page }
- { then you must call the routine with pa=1-PAGE! }
- { Again, the drawn pixel will _NOT_ automatically be taken }
- { over into the background image, that is: it will be visible }
- { only until the next animation cycle (=till calling ANIMATE) }
- { (For that reason, you should call this routine AFTER }
- { calling ANIMATE, because otherwise, your drawn pixel will }
- { vanish at once!) }
- { Sensible values for "pa" are either 0 or 1 (and evtl. BACK- }
- { GNDPAGE, if you are using background mode STATIC), however, }
- { the routine doesn't check that! }
- ASM
- CMP pa,BACKGNDPAGE
- JNE @doit
- PUSH x
- PUSH y
- PUSH WORD PTR color
- CALL BackgroundPutPixel
- JMP @offscrn
-
- @doit:
- CMP WinClip,TRUE
- JE @goClip
-
- MOV DI,y
- SUB DI,StartVirtualY {transform y into absolute coordinates}
- JS @offscrn
- CMP DI,YMAX
- JG @offscrn
- MOV BX,x
- SUB BX,StartVirtualX {transform x into absolute coordinates}
- JS @offscrn
- CMP BX,XMAX
- JG @offscrn
- SHL DI,1
- MOV DI,CS:[OFFSET gadr + DI]
- {DI = Y * LINESIZE, BX = X, coordinates admissible}
- MOV AX,BX
- SHR AX,1
- SHR AX,1
- ADD DI,AX {DI = Y * LINESIZE + (X SHR 2) }
- AND BX,3
- MOV AH,[OFFSET TranslateTab + BX]
- MOV AL,2
- MOV DX,3C4h
- MOV BX,pa {BX = graphic page}
- SHL BX,1
- MOV ES,[BX +OFFSET Segment_Adr+StartIndex*2]
-
- CLI
- OUT DX,AX
- MOV AL,color
- MOV ES:[DI],AL {faster than STOSB on >=386!}
- STI
- JMP @ende
-
- @goClip: {to this address, if clipping active}
- MOV DI,y
- SUB DI,StartVirtualY {transform y into absolute coordinates}
- CMP DI,WinYMIN
- JL @offscrn
- CMP DI,WinYMAX
- JG @offscrn
- MOV BX,x
- SUB BX,StartVirtualX {transform x into absolute coordinates}
- CMP BX,WinXMIN
- JL @offscrn
- CMP BX,WinXMAX
- JG @offscrn
- SHL DI,1
- MOV DI,CS:[OFFSET gadr + DI]
- {DI = Y * LINESIZE, BX = X, coordinates admissible}
- MOV AX,BX
- SHR AX,1
- SHR AX,1
- ADD DI,AX {DI = Y * LINESIZE + (X SHR 2) }
- AND BX,3
- MOV AH,[OFFSET TranslateTab + BX]
- MOV AL,2
- MOV DX,3C4h
- MOV BX,pa {BX = graphic page}
- SHL BX,1
- MOV ES,[BX +OFFSET Segment_Adr+StartIndex*2]
-
- CLI
- OUT DX,AX
- MOV AL,color
- MOV ES:[DI],AL {faster than STOSB on >=386!}
- STI
- @offscrn:
- @ende:
- END;
-
- PROCEDURE LoadFont(s:STRING);
- { in: s = name of the font file to load, '' for: internal font }
- { FontType = type of the actual font}
- {out: CurrentFont=pointer to new font }
- { FontType = type of the font loaded}
- { FontHeight=its height in rows }
- { FontWidth =its width in pixels }
- { FontProportion = TagProportional, if proportional font }
- { FontWidthTable[] = font widths for each letter }
- {The initial call to "ResetToInternalFont" assures that FontType }
- { always has a defined value when this routine gets called! }
-
- PROCEDURE ResetToInternalFont;
- VAR i,j:BYTE;
- BEGIN
- IF CurrentFont<>NIL {very first call? }
- THEN BEGIN {no! }
- IF FontType=TagMonoFont
- THEN FreeMem(CurrentFont,SizeOf(MonoFont))
- ELSE IF FontType=TagColorFont
- THEN FreeMem(CurrentFont,SizeOf(ColorFont))
- END;
- IF MaxAvail<SizeOf(MonoFont)
- THEN BEGIN {not even enough memory for internal font! }
- Error:=Err_NotEnoughMemory;
- exit
- END;
- GetMem(CurrentFont,SizeOf(MonoFont));
- FontType:=TagMonoFont;
- FontWidth:=6;
- FontHeight:=6;
- FontProportion:=0;
- FillChar(FontWidthTable,SizeOf(FontWidthTable),FontWidth);
- FOR i:=0 TO 255 DO
- FOR j:=0 TO FontHeight-1 DO
- MonoFont(CurrentFont^)[i][j]:=internalFont[i][j]
- END;
-
- VAR f:FileOfByte;
- CONST Tag:STRING='FNT';
- VAR Header:STRING[3];
- size,i,j:WORD;
- newFontWidth,newFontHeight,newFontType,newFontProp:BYTE;
- tempName:STRING;
- BEGIN
- IF s=''
- THEN BEGIN {switch to internal font }
- ResetToInternalFont;
- exit
- END;
-
- tempName:=FindFile(s);
- IF tempName<>'' THEN s:=tempName;
-
- {open font file and read in header: }
- _Assign(f,s);
- {$I-}
- _Reset(f);
- Header[0]:=CHAR(Length(Tag));
- _BlockRead(f,Header[1],Length(Tag));
- _BlockRead(f,newFontWidth,1);
- _BlockRead(f,newFontHeight,1);
- _BlockRead(f,newFontType,1);
- {$IFDEF IOcheck} {$I+} {$ENDIF}
-
- IF (IOresult<>0) OR (CompressError<>CompressErr_NoError)
- THEN BEGIN
- {$I-}
- _Close(f);
- {$IFDEF IOcheck} {$I+} {$ENDIF}
- Error:=Err_FileIO;
- CompressError:=CompressErr_NoError;
- exit;
- END;
-
- newFontProp:=newFontType AND TagProportional; {<>0, if proportional }
- newFontType:=newFontType AND Pred(TagProportional);
-
- size:=Length(Tag)+3; {length of header }
- IF newFontType=TagMonoFont
- THEN inc(size,((newFontWidth+7) SHR 3)*newFontHeight SHL 8)
- ELSE inc(size,newFontWidth*newFontHeight SHL 8); {256 chars }
-
- IF newFontProp=TagProportional THEN inc(size,256); {font widths}
-
- IF (Header<>Tag) OR
- ( (newFontType<>TagMonoFont) AND (newFontType<>TagColorFont) ) OR
- (newFontWidth>MaxFontWidth) OR
- (newFontHeight>MaxFontHeight) OR
- (_FileSize(f)<>size)
- THEN BEGIN {no FONT-file }
- Error:=Err_NoFont;
- {$I-}
- _Close(f);
- {$IFDEF IOcheck} {$I+} {$ENDIF}
- CompressError:=CompressErr_NoError;
- exit
- END;
-
- IF newFontType=TagMonoFont
- THEN size:=SizeOf(MonoFont)
- ELSE size:=SizeOf(ColorFont);
-
- {now release old memory and allocate new mem: }
- IF FontType<>newFontType
- THEN BEGIN {only necessary, if old and new fonts are different: }
- IF FontType=TagMonoFont THEN FreeMem(CurrentFont,SizeOf(MonoFont))
- ELSE {FontType=TagColorFont} FreeMem(CurrentFont,SizeOf(ColorFont));
- IF MaxAvail<size
- THEN BEGIN {not enough memory }
- Error:=Err_NotEnoughMemory;
- ResetToInternalFont;
- {$I-}
- _Close(f);
- {$IFDEF IOcheck} {$I+} {$ENDIF}
- exit
- END;
- GetMem(CurrentFont,size)
- END;
-
- FontWidth :=newFontWidth;
- FontHeight :=newFontHeight;
- FontType :=newFontType;
- FontProportion:=newFontProp;
-
- IF FontType=TagMonoFont
- THEN BEGIN
- FOR i:=0 TO 255 DO
- BEGIN
- Fillchar(MonoFont (CurrentFont^)[i],SizeOf(MonoFontChar),0);
- FOR j:=0 TO FontHeight-1 DO
- {$I-}
- _BlockRead(f,MonoFont(CurrentFont^)[i][j],(FontWidth+7) SHR 3);
- {$IFDEF IOcheck} {$I+} {$ENDIF}
- END;
- END
- ELSE FOR i:=0 TO 255 DO
- FOR j:=0 TO FontHeight-1 DO
- {$I-}
- _BlockRead(f,ColorFont(CurrentFont^)[i][j],FontWidth);
- {$IFDEF IOcheck} {$I+} {$ENDIF}
- {$I-}
- IF FontProportion=TagProportional
- THEN _BlockRead(F,FontWidthTable,SizeOf(FontWidthTable))
- ELSE FillChar(FontWidthTable,SizeOf(FontWidthTable),FontWidth);
- _Close(f);
- {$IFDEF IOcheck} {$I+} {$ENDIF}
- CompressError:=CompressErr_NoError; {reset evtl. compress error }
- END;
-
- FUNCTION OutTextLength(s:STRING):WORD;
- { text string }
- { Font* = the font describing datas}
- {out: Width of the given string in _pixels_; proportional fonts }
- { will be treated correctly }
- VAR i:BYTE;
- temp:WORD;
- BEGIN
- IF FontProportion=TagProportional
- THEN BEGIN
- temp:=0;
- FOR i:=1 TO length(s) DO inc(temp,FontWidthTable[BYTE(s[i])]);
- END
- ELSE temp:=FontWidth*length(s);
- OutTextLength:=temp
- END;
-
- PROCEDURE OutTextXY(x,y:INTEGER; pa:WORD; s:STRING);
- { in: (x,y) = (virtual) starting coordinates for the text to be written}
- { s = textstring to be displayed }
- { pa = graphic page where the text shall be written }
- { GraphTextColor=color for text }
- { GraphTextBackground=color to be used for text background; if }
- { this value equals GraphTextColor, only the text-pixels }
- { themselves will be drawn while the surrounding ones }
- { don't change (=normal behaviour of TP's OutText-procs) }
- { GraphTextOrientation="vertical" or "horizontal" }
- { StartVirtualX,StartVirtualY = upper left image corner }
- { Font* = the font describing datas}
- {out: text has been written to the screen }
- VAR offs,z,bit,i,CharWidth:BYTE;
- data1:MonoFontchar;
- data2:ColorFontChar;
- b:WORD;
- BEGIN
- IF (pa<0) OR (pa>SCROLLPAGE)
- THEN BEGIN
- Error:=Err_InvalidPageNumber;
- exit
- END;
- IF (pa=BACKGNDPAGE) AND EMSused
- THEN EMSFillFrame(BackgroundEMSHandle); {prepare EMS access }
- offs:=MaxFontWidth-FontWidth;
- IF (FontType=TagMonoFont)
- THEN FOR i:=1 TO Length(s) DO
- BEGIN
- data1:=MonoFont(CurrentFont^)[BYTE(s[i])];
- CharWidth:=FontWidthTable[BYTE(s[i])];
- FOR z:=0 TO FontHeight-1 DO
- BEGIN
- b:=WORD(data1[z]);
- FOR bit:=0 TO CharWidth-1 DO
- IF b and FontMask[bit+offs]<>0
- THEN PagePutPixel(x+bit,y+z,GraphTextColor,pa)
- ELSE IF (GraphTextColor<>GraphTextBackground)
- THEN PagePutPixel(x+bit,y+z,GraphTextBackground,pa);
- END;
- IF GraphTextOrientation=horizontal
- THEN INC(x,CharWidth)
- ELSE INC(y,FontHeight);
- END
- ELSE FOR i:=1 TO Length(s) DO
- BEGIN
- data2:=ColorFont(CurrentFont^)[BYTE(s[i])];
- CharWidth:=FontWidthTable[BYTE(s[i])];
- FOR z:=0 TO FontHeight-1 DO
- FOR bit:=0 TO CharWidth-1 DO
- BEGIN
- b:=data2[z][bit];
- IF b<>0 THEN PagePutPixel(x+bit,y+z,b,pa)
- ELSE IF (GraphTextColor<>GraphTextBackground)
- THEN PagePutPixel(x+bit,y+z,GraphTextBackground,pa);
- END;
- IF GraphTextOrientation=horizontal
- THEN INC(x,CharWidth)
- ELSE INC(y,FontHeight);
- END
- END;
-
- PROCEDURE BackgroundOutTextXY(x,y:INTEGER; s:STRING);
- {rem: Functionally equivalent to OutTextXY(), but the text will be }
- { written to the background page instead of page PAGEADR! }
- { Because BACKGNDADR is used as background page, calling }
- { this routine only makes sense when using mode STATIC!}
- VAR offs,z,bit,i,CharWidth:BYTE;
- data1:MonoFontchar;
- data2:ColorFontChar;
- b:WORD;
- BEGIN
- IF EMSused
- THEN EMSFillFrame(BackgroundEMSHandle); {prepare EMS access }
- offs:=MaxFontWidth-FontWidth;
- IF (FontType=TagMonoFont)
- THEN FOR i:=1 TO Length(s) DO
- BEGIN
- data1:=MonoFont(CurrentFont^)[BYTE(s[i])];
- CharWidth:=FontWidthTable[BYTE(s[i])];
- FOR z:=0 TO FontHeight-1 DO
- BEGIN
- b:=WORD(data1[z]);
- FOR bit:=0 TO CharWidth-1 DO
- IF b and FontMask[bit+offs]<>0
- THEN BackgroundPutPixel(x+bit,y+z,GraphTextColor)
- ELSE IF (GraphTextColor<>GraphTextBackground)
- THEN BackgroundPutPixel(x+bit,y+z,GraphTextBackground);
- END;
- IF GraphTextOrientation=horizontal
- THEN INC(x,CharWidth)
- ELSE INC(y,FontHeight);
- END
- ELSE FOR i:=1 TO Length(s) DO
- BEGIN
- data2:=ColorFont(CurrentFont^)[BYTE(s[i])];
- CharWidth:=FontWidthTable[BYTE(s[i])];
- FOR z:=0 TO FontHeight-1 DO
- FOR bit:=0 TO CharWidth-1 DO
- BEGIN
- b:=data2[z][bit];
- IF b<>0 THEN BackgroundPutPixel(x+bit,y+z,b)
- ELSE IF (GraphTextColor<>GraphTextBackground)
- THEN BackgroundPutPixel(x+bit,y+z,GraphTextBackground);
- END;
- IF GraphTextOrientation=horizontal
- THEN INC(x,CharWidth)
- ELSE INC(y,FontHeight);
- END
- END;
-
- PROCEDURE MakeTextSprite(s:STRING; nr:WORD);
- { in: s = text which shall be converted into a sprite}
- { nr = spriteLOADnumber for the sprite to be generated}
- { Font*, CurrentFont = actual font }
- { GraphTextOrientation = orientation of the font}
- {Sprite?[nr] has been defined so, that it represents the contents }
- { of "s" as a sprite}
- {rem: The routine behaves like LoadSprite() }
- CONST DefaultHeader:SpriteHeader=
- (Zeiger_auf_Plane:(0,0,0,0);
- Breite_in_4er_Gruppen:0;
- Hoehe_in_Zeilen:0;
- Translate:(1,2,4,8);
- SpriteLength:0;
- Dummy:(0,0,0,0,0,0,0,0,0,0);
- Kennung:'KR';
- Version:1;
- Modus:Display_NORMAL;
- ZeigerL:0;
- ZeigerR:0;
- ZeigerO:0;
- ZeigerU:0
- );
- VAR header:SpriteHeader;
- p1,p2:POINTER;
- segm,offs,b:WORD;
- x,y,i:INTEGER;
- z,wert,bit,CharWidth:BYTE;
- data1:MonoFontchar;
- data2:ColorFontChar;
- BEGIN
- IF (nr=0) or (nr>LoadMAX)
- THEN BEGIN
- Error:=Err_InvalidSpritenumber;
- Exit
- END;
- header:=DefaultHeader; {use standard values }
- WITH header DO
- BEGIN
- IF GraphTextOrientation=horizontal
- THEN BEGIN {sprite height is only 1 char cell}
- Hoehe_in_Zeilen:=FontHeight;
- Breite_in_4er_Gruppen:=(OutTextLength(s)+3) SHR 2
- END
- ELSE BEGIN {sprite width is only 1 char cell}
- Hoehe_in_Zeilen:=FontHeight*Length(s);
- Breite_in_4er_Gruppen:=(FontWidth+3) SHR 2
- END;
- SpriteLength:=Kopf+ {size of sprite header}
- 2*(2*Hoehe_in_Zeilen)+ {le. & ri. boundaries }
- 2*(2*4*Breite_in_4er_Gruppen)+ {up. & lo. boundaries }
- Breite_in_4er_Gruppen*4*Hoehe_in_Zeilen; {data}
- IF (Breite_in_4er_Gruppen*Hoehe_in_Zeilen=0)
- OR (SpriteLength>65521-15) {GetMem-upper bound=65521}
- THEN BEGIN
- Error:=Err_NoSprite;
- Exit
- END;
- {enough space left? }
- IF (Header.SpriteLength+15>MaxAvail+SPRITESIZE[nr])
- THEN BEGIN
- Error:=Err_NotEnoughMemory;
- Exit
- END
- ELSE FreeSpriteMem(nr); {evtl. release old memory }
-
- getmem(p1,Header.SpriteLength+15); {get enough space }
- SPRITESIZE[nr]:=Header.SpriteLength+15;
- SPRITEPTR [nr]:=p1;
- IF (LONGINT(p1) mod 16)=0
- THEN p2:=p1 {make p2 fall on segment boundary}
- ELSE LONGINT(p2):=LONGINT(p1) + (16-LONGINT(p1) mod 16);
- segm:=LONGINT(p2) SHR 16 +(LONGINT(p2) AND 65535) SHR 4;
- SPRITEAD[nr]:=segm;
-
- ZeigerL:=Kopf;
- ZeigerR:=ZeigerL+Hoehe_in_Zeilen*2;
- ZeigerO:=ZeigerR+Hoehe_in_Zeilen*2;
- ZeigerU:=ZeigerO+(Breite_in_4er_Gruppen*4)*2;
- FOR i:=0 TO 3 DO
- Zeiger_auf_Plane[i]:=ZeigerU+(Breite_in_4er_Gruppen*4)*2+
- i*Breite_in_4er_Gruppen*Hoehe_in_Zeilen;
- FOR i:=0 TO Hoehe_in_Zeilen-1 DO
- BEGIN
- MEMW[segm:ZeigerL +i SHL 1]:=+16000;
- MEMW[segm:ZeigerR +i SHL 1]:=WORD(-16000);
- END;
- FOR i:=0 TO Breite_in_4er_Gruppen*4-1 DO
- BEGIN
- MEMW[segm:ZeigerO +i SHL 1]:=+16000;
- MEMW[segm:ZeigerU +i SHL 1]:=WORD(-16000);
- END;
-
- MOVE(Header,p2^,Kopf); {store sprite header to heap }
-
- {now compute sprite data: do this by drawing pixels into the memory}
- offs:=MaxFontWidth-FontWidth; x:=0; y:=0;
- IF (FontType=TagMonoFont)
- THEN FOR i:=1 TO Length(s) DO
- BEGIN
- data1:=MonoFont(CurrentFont^)[BYTE(s[i])];
- CharWidth:=FontWidthTable[BYTE(s[i])];
- FOR z:=0 TO FontHeight-1 DO
- BEGIN
- b:=WORD(data1[z]);
- FOR bit:=0 TO CharWidth-1 DO
- BEGIN
- IF b and FontMask[bit+offs]<>0
- THEN wert:=GraphTextColor
- ELSE IF (GraphTextColor<>GraphTextBackground)
- THEN wert:=GraphTextBackground
- ELSE wert:=0;
- {pixel (a,b) -> b*Breite_in_4er_Gruppen+(x div 4) at plane x mod 4 }
- MEM[segm:Zeiger_auf_Plane[(x+bit) AND 3]+
- (y+z)*Breite_in_4er_Gruppen+
- (x+bit) SHR 2]:=wert;
- IF wert<>0
- THEN BEGIN {evtl. re-compute boundaries}
- IF x+bit<INTEGER(MEMW[segm:ZeigerL +(y+z) SHL 1])
- THEN MEMW[segm:ZeigerL +(y+z) SHL 1]:=x+bit;
- IF x+bit>INTEGER(MEMW[segm:ZeigerR +(y+z) SHL 1])
- THEN MEMW[segm:ZeigerR +(y+z) SHL 1]:=x+bit;
- IF y+z<INTEGER(MEMW[segm:ZeigerO +(x+bit) SHL 1])
- THEN MEMW[segm:ZeigerO +(x+bit) SHL 1]:=y+z;
- IF y+z>INTEGER(MEMW[segm:ZeigerU +(x+bit) SHL 1])
- THEN MEMW[segm:ZeigerU +(x+bit) SHL 1]:=y+z;
- END;
- END;
- END;
- IF GraphTextOrientation=horizontal
- THEN INC(x,CharWidth)
- ELSE INC(y,FontHeight);
- END
- ELSE FOR i:=1 TO Length(s) DO
- BEGIN
- data2:=ColorFont(CurrentFont^)[BYTE(s[i])];
- CharWidth:=FontWidthTable[BYTE(s[i])];
- FOR z:=0 TO FontHeight-1 DO
- FOR bit:=0 TO CharWidth-1 DO
- BEGIN
- b:=data2[z][bit];
- IF b<>0 THEN wert:=b
- ELSE IF (GraphTextColor<>GraphTextBackground)
- THEN wert:=GraphTextBackground
- ELSE wert:=0;
- {pixel (a,b) -> b*Breite_in_4er_Gruppen+(x div 4) at plane x mod 4 }
- MEM[segm:Zeiger_auf_Plane[(x+bit) AND 3]+
- (y+z)*Breite_in_4er_Gruppen+
- (x+bit) SHR 2]:=wert;
-
- IF wert<>0
- THEN BEGIN {evtl. re-compute boundaries}
- IF x+bit<INTEGER(MEMW[segm:ZeigerL +(y+z) SHL 1])
- THEN MEMW[segm:ZeigerL +(y+z) SHL 1]:=x+bit;
- IF x+bit>INTEGER(MEMW[segm:ZeigerR +(y+z) SHL 1])
- THEN MEMW[segm:ZeigerR +(y+z) SHL 1]:=x+bit;
- IF y+z<INTEGER(MEMW[segm:ZeigerO +(x+bit) SHL 1])
- THEN MEMW[segm:ZeigerO +(x+bit) SHL 1]:=y+z;
- IF y+z>INTEGER(MEMW[segm:ZeigerU +(x+bit) SHL 1])
- THEN MEMW[segm:ZeigerU +(x+bit) SHL 1]:=y+z;
- END;
- END;
- IF GraphTextOrientation=horizontal
- THEN INC(x,CharWidth)
- ELSE INC(y,FontHeight);
- END
-
- END; {of WITH}
-
- END;
-
- FUNCTION Hitdetect(s1,s2:INTEGER):BOOLEAN; ASSEMBLER;
- { in: s1,s2 = sprite position numbers of two sprites}
- { SpriteN[s1],SpriteX[s1],SpriteY[s1] = sprite data of sprite s1 }
- { SpriteN[s2],SpriteX[s2],SpriteY[s2] = sprite data of sprite s2 }
- {out: TRUE/FALSE for "sprites collide"/"sprites do not collide" }
- {rem: This check is pixel-precise and doesn't depend on the sprites being }
- { visible (=onscreen) or not! }
- { inactive sprites (SpriteN[s?]=0) cannot collide }
- { A sprite can't collide with itself, (thus: s1=s2 -> FALSE) }
- ASM
- MOV SI,s1 {get 1st parameter s1 from stack}
- MOV DI,s2 {get 2nd parameter s2 from stack}
- CMP SI,DI
- JE @NOHIT1 {sprite can't collide with itself }
- SHL SI,1
- mov cx,[SI + OFFSET SpriteN]
- jcxz @NOHIT1 {sprite <>0, that is: sprite active?}
- SHL DI,1
- MOV BX,[DI + OFFSET SpriteN]
- OR BX,BX {dto. for other sprite }
- JNE @PRUEF2
- @NOHIT1:
- JMP @NOHIT7 {inactive sprites can't collide }
- {either -> return FALSE }
- {here: SI (DI) = pointer to 1. (2.) sprite in ?YWRTD[..],}
- { CX (BX) = spritenumber of sprite 1 (2) }
- {(a bit later, DS (ES) becomes segment addr. of sprite data of spr. 1 (2) )}
- @PRUEF2:
- MOV AX,[SI + OFFSET SpriteY]
- MOV DX,[DI + OFFSET SpriteY]
- mov si,[SI + OFFSET SpriteX] {SI = x1}
- mov di,[DI + OFFSET SpriteX] {DI = x2}
- shl bx,1 {BX = sprite number2 * 2}
- mov es,[BX + OFFSET SPRITEAD] {ES = segment of 2nd sprite's data}
- mov bx,cx {(CX = spritenumber1)}
- shl bx,1 {BX = spritenumber1 * 2}
- MOV ds,[BX + OFFSET SPRITEAD]
-
- mov [y1],ax
- mov [y2],dx
- sub dx,ax
- mov CS:WORD PTR @y2_y1+1,dx
- mov [x1],si
- mov [x2],di
- mov dx,di
- sub dx,si
- mov CS:WORD PTR @x2_x1+1,dx
- mov ax,es:[Left] {AX = pointer to left boundary data}
- mov CS:WORD PTR @lirand2+1,ax
- mov ax,es:[Right] {AX = pointer to right boundary data}
- mov CS:WORD PTR @rerand2+1,ax
- mov ax,es:[Top] {AX = pointer to upper boundary data}
- mov CS:WORD PTR @orand2+1,ax
- mov ax,es:[Bottom] {AX = pointer to lower boundary data}
- mov CS:WORD PTR @urand2+1,ax
- mov ax,es:[Breite] {AX = max. width in groups of 4 }
- shl al,1
- shl al,1
- mov CS:WORD PTR @breite2+1,ax {*4 = width in points }
- mov ax,es:[Hoehe]
- mov CS:WORD PTR @hoehe2+1,ax {height of sprite2 in points}
-
- MOV AX,[Left] {AX = pointer to left boundary data}
- MOV CS:WORD PTR @LIRAND1+1,AX
- MOV AX,[Right] {AX = pointer to right boundary data}
- MOV CS:WORD PTR @RERAND1+1,AX
- MOV AX,[Top] {AX = pointer to upper boundary data}
- MOV CS:WORD PTR @ORAND1+1,AX
- MOV AX,[Bottom] {AX = pointer to lower boundary data}
- MOV CS:WORD PTR @URAND1+1,AX
- MOV BX,[Breite] {BX = max. width in groups of 4 }
- SHL BX,1
- SHL BX,1 {*4 = width in points }
- MOV CS:WORD PTR @BREITE1+2,BX
-
- lea bx,[si+bx-1] {BX := x1 + breite1 - 1 (=x1last)}
- @breite2:
- mov bp,1234h {dummy value}
- mov cx,bp {CX = breite2 will be needed again later on}
- lea bp,[di+bp-1] {BP := x2 + breite2 - 1 (=x2last)}
- cmp bx,bp
- jle @noex1
- mov bp,bx
- @noex1: {here: BP = max(x1last,x2last) (=maxx)}
- cmp si,di
- jle @X1_klgl_X2
- xchg si,di
- @X1_klgl_X2: {here: SI = min(x1,x2) (=minx)}
- stc
- sbb si,bp {SI := minx - maxx - 1 = - (maxx - minx + 1)}
- @breite1:
- add cx,1234h {(dummy value) CX := breite1 + breite2}
- add cx,si {CX := breite1 + breite2 - (maxx - minx + 1)}
- dec cx {CX := breite1 + breite2 - (maxx - minx + 1) - 1 (=ueberlappx - 1)}
- js @NOHIT2 {no collision, if ueberlappx <= 0 }
- mov [ueberlappx_1],cx
-
- mov ax,[Hoehe]
- mov bx,ax {BX := hoehe1}
- mov di,[y1] {DI := y1}
- add ax,di {AX := y1 + hoehe1}
- dec ax {AX := y1 + hoehe1 - 1 (=y1last)}
- @hoehe2:
- mov si,1234h
- mov dx,[y2]
- add dx,si {DX := y2 + hoehe2}
- dec dx {DX := y2 + hoehe2 - 1 (=y2last)}
- cmp ax,dx
- jge @noex2
- mov ax,dx
- @noex2: {here: AX = max(y1last,y2last) (=maxy)}
- mov dx,[y2]
- cmp di,dx {(DI = y1)}
- jle @noex3
- mov di,dx
- @noex3: {here: DI = min(y1,y2) (=miny)}
- sub di,ax {DI := miny - maxy = - (maxy - miny)}
- lea ax,[bx+si-2] {AX := hoehe1 + hoehe2 - 2}
- add ax,di {AX := hoehe1 + hoehe2 - (maxy - miny + 1) - 1 (=ueberlappy - 1)}
- js @NOHIT2 {no collision, if ueberlappy <= 0 }
- mov [ueberlappy_1],ax
-
- {here: AX = ueberlappy - 1, CX = ueberlappx - 1}
- @x2_x1:
- mov dx,1234h {dummy value}
- xor bx,bx {from now on: BX = 0 !}
- or dx,dx
- js @X2_X1_kl_0 {if x2 - x1 >= 0 then...}
- mov [hit2xfirst],bx {...hit2xfirst := 0}
- mov [hit1xfirst],dx {...hit1xfirst := x2 - x1}
- jmp @Yhits {SHORT}
-
- {jump-rail for NOHIT (this is a good place)}
- @NOHIT2:
- JMP @NOHIT7
-
- {now back at "normal" program }
- @X2_X1_kl_0: {else (x2 - x1 < 0)...}
- mov [hit1xfirst],bx {...hit1xfirst := 0}
- neg dx {DX := x1 - x2}
- mov [hit2xfirst],dx {...hit2xfirst := x1 - x2}
-
- @Yhits: {here: AX = ueberlappy - 1}
- @y2_y1:
- mov dx,1234h {dummy value}
- or dx,dx
- js @Y2_Y1_kl_0 {if y2 - y1 >= 0 then...}
- mov [hit2yfirst],bx {...hit2yfirst := 0}
- mov [hit1yfirst],dx {...hit1yfirst := y2 - y1}
- jmp @iterate {SHORT}
- @Y2_Y1_kl_0: {else (y2 - y1 < 0)...}
- mov [hit1yfirst],bx {...hit1yfirst := 0}
- neg dx {DX := y1 - y2}
- mov [hit2yfirst],dx {...hit2yfirst := y1 - y2}
-
- {Now check the overlapping rows and columns more closely by iteration: }
- @iterate:
- mov cx,[ueberlappy_1] {number of rows -1 to compare }
- shl cx,1 {*2, because word-sized!}
- @lirand1:
- mov si,1234h {dummy value}
- @lirand2:
- mov di,1234h {dummy value}
- @rerand1:
- mov bx,1234h {dummy value}
- @rerand2:
- mov bp,1234h {dummy value}
- sub bx,si {BX := rerand1 - lirand1}
- sub bp,di {BP := rerand2 - lirand2}
- mov ax,[hit1yfirst]
- shl ax,1
- add si,ax {SI := 1st row where sprite1 overlaps sprite2 }
- mov ax,[hit2yfirst]
- shl ax,1
- add di,ax {DI := 1st row where sprite2 overlaps sprite1 }
- add si,cx {dto., last row }
- add di,cx
- @one_line:
- mov ax,[si] {DS:AX := x1li[row] }
- mov dx,es:[di] {ES:DX := x2li[row] }
- add ax,[x1] {AX := x1li[row] + x1 (=c) }
- add dx,[x2] {DX := x2li[row] + x2 (=d) }
- cmp ax,dx
- jge @C_grgl_D
- mov ax,dx
- @C_grgl_D: {here: AX = max(c,d)}
- mov cx,[si+bx] {DS:CX := x1re[row] }
- mov dx,es:[di+bp] {ES:DX := x2re[row] }
- add cx,[x1] {CX := x1re[row] + x1 (=a) }
- add dx,[x2] {DX := x2re[row] + x2 (=b) }
- cmp cx,dx
- jle @A_klgl_B
- mov cx,dx
- @A_klgl_B: {here: CX = min(a,b)}
- cmp cx,ax {min(a,b) >= max(c,d) ?}
- jge @found_Xhit {yes: collision in X-direction found!}
- dec si {next row (-> word-sized values!)}
- dec si
- dec di
- dec di
- dec WORD PTR [ueberlappy_1]
- jns @one_line
- {no collision in X-direction -> no collision at all! }
- jmp @NOHIT7
-
- {otherwise: collision in X-direction, now check Y-dir. also (as above) and }
- {report "collision!" only, if there is at least 1 collision in Y-dir., too }
- @found_Xhit:
- mov cx,[ueberlappx_1] {number of columns -1 to compare }
- shl cx,1 {*2, because word-sized!}
- @orand1:
- mov si,1234h {dummy value}
- @orand2:
- mov di,1234h {dummy value}
- @urand1:
- mov bx,1234h {dummy value}
- @urand2:
- mov bp,1234h {dummy value}
- sub bx,si {BX := urand1 - orand1}
- sub bp,di {BP := urand2 - orand2}
- mov ax,[hit1xfirst]
- shl ax,1 {*2, because word-sized!}
- add si,ax {SI := orand1 + 2 * hit1xfirst}
- mov ax,[hit2xfirst]
- shl ax,1 {*2, because word-sized!}
- add di,ax {DI := orand2 + 2 * hit2xfirst}
- add si,cx
- add di,cx
- @one_column: mov ax,[si] {AX := y1ob[column]}
- cmp ax,16000 {dummy value for "empty column"?}
- je @next_column {yes, thus: surely no collision }
- mov dx,es:[di] {DX := y2ob[column]}
- cmp dx,16000 {check 2nd sprite too: "empty column"?}
- je @next_column {yes, no collision}
- add ax,[y1] {AX := y1ob + y1 (=c)}
- add dx,[y2] {DX := y2ob + y2 (=d)}
- cmp ax,dx
- jge @C_grgl_D2
- mov ax,dx
- @C_grgl_D2: {here: AX = max(c,d)}
- mov cx,[si+bx] {DS:CX := y1un[column]}
- mov dx,es:[di+bp] {ES:DX := y2un[column]}
- add cx,[y1] {CX := y1un + y1 (=a)}
- add dx,[y2] {DX := y2un + y2 (=b)}
- cmp cx,dx
- jle @A_klgl_B2
- mov cx,dx
- @A_klgl_B2: {here: CX = min(a,b)}
- cmp cx,ax {min(a,b) >= max(c,d) ?}
- jge @HIT2 {yes: collision detected!}
- @next_column:
- dec si {no, next column (-> word-sized values!)}
- dec si
- dec di
- dec di
- dec WORD PTR [ueberlappx_1]
- jns @one_column
-
- @NOHIT7:
- XOR AX,AX {return 0 = FALSE as result }
- JMP @TREFF_END {SHORT}
- @HIT2:
- MOV AX,1 {return 1 = TRUE as result }
-
- @TREFF_END:
- {$IFOPT G+}
- mov bp,sp {only necessary for compiler switch G+!}
- {$ENDIF}
- mov dx,seg @DATA {else, BP will be restored by TP itself}
- mov ds,dx
- END;
-
- PROCEDURE SetSplitIndex(number:INTEGER);
- { in: number = index number of the sprite, up to which sprites won't }
- { be clipped to the animation windows }
- {out: - }
- {rem: After calling the routine, sprites SpriteN[0..number] will not-}
- { and SpriteN[number+1..NMAX] will be clipped to the animation window}
- { If number <0 oder >NMAX, then all sprites will be clipped!}
- BEGIN
- IF number>NMAX THEN number:=-1;
- SplitIndex:=number;
- SplitIndex_mal2:=number*2
- END;
-
- FUNCTION GetSplitIndex:INTEGER;
- { in: - }
- {out: Actually set value of SplitIndex }
- BEGIN
- GetSplitIndex:=SplitIndex
- END;
-
- PROCEDURE SetAnimateWindow(x1,y1,x2,y2:INTEGER);
- { in: (x1,y1) = left upper corner of the animation window to set }
- { (x2,y2) = dto., lower right corner}
- {out: Win* have been updated accordingly }
- { BWin* = backups of the most important values}
- {rem: The points must be specified in absolute coordinates }
- { The window's size must at least be 32x32 pixels, }
- { x1 and x2-x1+1 must be multiples of 4 (or they will be made so)! }
- BEGIN
- x1:=x1 AND $FFFC; {make x1 a multiple of 4 }
- WinXMIN:=x1; WinXMINdiv4:=x1 SHR 2;
- WinYMIN:=y1; WinYMIN_mul_LINESIZE:=y1*LINESIZE;
- WinYMINmLINESIZEaWinXMINdiv4:=WinYMIN_mul_LINESIZE+WinXMINdiv4;
- WinWidth :=succ(x2-x1) AND $FFFC; {make the width a multiple of 4 }
- WinHeight:=succ(y2-y1);
- WinXMAX:=WinXMIN+WinWidth-1;
- WinYMAX:=WinYMIN+WinHeight-1;
- WinWidthDiv4:=WinWidth SHR 2;
- WinLowerRight:=(XMAX-WinXMAX) SHR 2 + (YMAX-WinYMAX)*LINESIZE;
- IF (WinXMIN<0) OR (WinYMIN<0) OR (WinWidth<32) OR (WinHeight<32) OR
- (WinXMAX>XMAX) OR (WinYMAX>YMAX)
- THEN Error:=Err_InvalidCoordinates;
-
- BWinXMIN:=WinXMIN; {make backups }
- BWinYMIN:=WinYMIN;
- BWinXMAX:=WinXMAX;
- BWinYMAX:=WinYMAX;
- BWinLowerRight:=WinLowerRight;
- BWinYMIN_mul_LINESIZE:=WinYMIN_mul_LINESIZE
- END;
-
- PROCEDURE Animate;
- { in: PAGEADR = actual graphicpage(address) on which to draw upon }
- { BACKGNDADR = background page(address) }
- { BACKGROUNDMODE = STATIC/SCROLLING for solid/scrollable background }
- { SpriteN[] = spritenumber of sprite to be displayed }
- { SpriteX[],SpriteY[] = their (virtual) coordinates }
- { StartVirtualX,StartVirtualY = upper left image corner }
- { (PAGE = actually displayed graphic page) }
- { Win* = data describing the animation window }
- {out: PAGE = 0/1, if PAGE has been 1/0, respectively }
- { PAGEADR = new, actual graphic page(address) }
- {rem: Animate erases the old contents of the page (using the background page }
- { information), draws all visible sprites, synchronizes to the display- }
- { enable signal and switches the display to that now completed page }
- VAR leftcut,rightcut,topcut,bottomcut:WORD;
- {x,y,} xtil,ytil,actindex:INTEGER;
-
- KachelnWegLinks,KachelnWegOben,
- innerTilesX,innerTilesY,
- stepX1,stepX2,
- Xoffscreen,Yoffscreen,
- counter,
- Korrektur,
- BytesPerPlane,LINESIZE_sub_BytesPerPlane,
- leftcutDIV4,
- tempActIndex,tempDI,tempXtil,tempYtil,{tempX,tempY,}
- oldActIndex,oldDI,
- StartWritePlane,StartLesePlane: INTEGER;
- BEGIN
- IF EMSused AND (BackgroundMode=STATIC)
- THEN EMSFillFrame(BackgroundEMSHandle); {prepare EMS access }
- ASM
- CLD
- {first copy the background picture to the actual graphic page:}
- CMP BackgroundMode,STATIC {which background mode? }
- JE @static_bckgnd
- JMP @scrolling_bckgnd
-
- @static_bckgnd:
- MOV BX,WinHeight
- MOV DX,WinWidth
- MOV SI,WinYMINmLINESIZEaWinXMINdiv4 {1.1st start/dest. address}
- MOV DI,SI
-
- MOV ES,PAGEADR {fill graphic page with background pattern}
- CMP UpdateOuterArea,0 {update outer background area?}
- MOV DS,BACKGNDADR
-
- je @skip_outer
- {do inner and outer background area in one }
- xor si,si
- xor di,di
-
- mov ax,0102h
- mov dx,3c4h
- mov bx,pagesize/2
- out dx,ax {write plane 0 }
- mov cx,bx
- rep movsw
- mov ah,2
- out dx,ax {write plane 1 }
- mov cx,bx
- xor di,di
- rep movsw
- mov ah,4
- out dx,ax {write plane 2 }
- mov cx,bx
- xor di,di
- rep movsw
- mov ah,8
- out dx,ax {write plane 3 }
- mov cx,bx
- xor di,di
- rep movsw
- mov ax,seg @data
- mov ds,ax
- dec UpdateOuterArea
- jmp @sprites_zeichnen
- @skip_outer: {draw only inner area}
-
- PUSH BP
-
- CMP DX,XMAX+1 {window from the very left to the very right?}
- JNE @innen
-
- MOV AX,0102h
- MOV DX,3C4h
- SHL BX,1 {yes, can be done by a REP MOVSB instruction }
- MOV BX,CS:[OFFSET gadr + BX] {BX := WinHeight * LINESIZE}
- MOV BP,PAGESIZE
- SUB BP,BX
-
- OUT DX,AX {select write plane 0 }
- MOV CX,BX
- SHR CX,1
- REP MOVSW
- ADC CX,CX
- REP MOVSB
- SUB DI,BX {reset DI }
- ADD SI,BP {set si to the next "plane" }
-
- MOV AH,2
- OUT DX,AX {select write plane 1 }
- MOV CX,BX
- SHR CX,1
- REP MOVSW
- ADC CX,CX
- REP MOVSB
- SUB DI,BX {reset DI }
- ADD SI,BP {set si to the next "plane" }
-
- MOV AH,4
- OUT DX,AX {select write plane 2 }
- MOV CX,BX
- SHR CX,1
- REP MOVSW
- ADC CX,CX
- REP MOVSB
- SUB DI,BX {reset DI }
- ADD SI,BP {set si to the next "plane" }
-
- MOV AH,8
- OUT DX,AX {select write plane 3 }
- MOV CX,BX
- SHR CX,1
- REP MOVSW
- ADC CX,CX
- REP MOVSB
-
- jmp @end_static
-
- @innen:
- SHR DX,1
- SHR DX,1 {DX := bytes per row }
- MOV BP,LINESIZE
- SUB BP,DX {BP := offset to the next row }
- MOV BH,DL
- XOR CH,CH
-
- MOV AX,0102h
- MOV DX,3C4h
- OUT DX,AX {select write plane 0 }
-
- MOV AH,BL
-
- PUSH SI
- PUSH DI
- @loop_innen1:
- MOV CL,BH
- SHR CX,1
- REP MOVSW
- ADC CX,CX
- REP MOVSB {move data of one row }
- ADD SI,BP {position to next row }
- ADD DI,BP
- DEC BL {one row completed}
- JNZ @loop_innen1
- POP DI
- POP SI
-
- ADD SI,PAGESIZE
- PUSH SI
- PUSH DI
- MOV BL,AH
- MOV AH,02h
- OUT DX,AX
- MOV AH,BL
- @loop_innen2:
- MOV CL,BH
- SHR CX,1
- REP MOVSW
- ADC CX,CX
- REP MOVSB {move data of one row }
- ADD SI,BP {position to next row }
- ADD DI,BP
- DEC BL {one row completed}
- JNZ @loop_innen2
- POP DI
- POP SI
-
- ADD SI,PAGESIZE
- PUSH SI
- PUSH DI
- MOV BL,AH
- MOV AH,04h
- OUT DX,AX
- MOV AH,BL
- @loop_innen3:
- MOV CL,BH
- SHR CX,1
- REP MOVSW
- ADC CX,CX
- REP MOVSB {move data of one row }
- ADD SI,BP {position to next row }
- ADD DI,BP
- DEC BL {one row completed}
- JNZ @loop_innen3
- POP DI
- POP SI
-
- ADD SI,PAGESIZE
- MOV BL,AH
- MOV AH,08h
- OUT DX,AX
- MOV AH,BL
- @loop_innen4:
- MOV CL,BH
- SHR CX,1
- REP MOVSW
- ADC CX,CX
- REP MOVSB {move data of one row }
- ADD SI,BP {position to next row }
- ADD DI,BP
- DEC BL {one row completed}
- JNZ @loop_innen4
-
- @end_static:
- POP BP
- MOV AX,SEG @DATA
- MOV DS,AX
-
- JMP @Sprites_zeichnen
-
- {---------------------------------}
-
- @scrolling_bckgnd: {now: create background image from tiles }
-
- {Do we have to redraw the outer area of the animation window?}
- cmp UpdateOuterArea,0
- je @old_scrolling_bckgnd
- {Yes, but perhaps there is nothing to draw at all?:}
- mov bx,WinHeight
- dec bx
- mov bh,bl
- mov bl,WinWidthDiv4
- mov ax,WinYMINmLINESIZEaWinXMINdiv4
- {BL=WinWidthDiv4, BH=WinHeight-1, AX=WinYMIN*LINESIZE+WinXMIN DIV 4}
- or ax,ax {upper left corner of the window = pixel (0,0)?}
- jne @do_outer {no: draw outer area }
- cmp bx,YMAX SHL 8 +LINESIZE {lower right corner = pixel (XMAX,YMAX)?}
- je @old_scrolling_bckgnd {yes, thus no outer area to draw }
-
- @do_outer: {now draw the outer area }
- {╔════════════════╗ outer area is divided into 3 regions: }
- {║1111111111111111║ }
- {║1111111111111111║ }
- {║111┌───────┐2222║ }
- {║222│ │2222║ }
- {║222│ │2222║ }
- {║222└───────┘3333║ }
- {║3333333333333333║ }
- {║3333333333333333║ }
- {╚════════════════╝ }
-
- {BL=WinWidthDiv4, BH=WinHeight-1, AX=WinYMIN*LINESIZE+WinXMIN DIV 4}
- push bp
- push WinLowerRight
- mov bp,ax
- mov es,PAGEADR
- mov ds,BACKGNDADR
- mov dx,3C4h
- mov ax,0102h {write plane 0 }
- out dx,ax
- xor si,si {region 1 starts at offset 0 }
- xor di,di
- mov cx,bp
- shr cx,1
- rep movsw
- adc cx,cx
- rep movsb
-
- mov ah,2 {write plane 1 }
- out dx,ax
- mov si,1*PAGESIZE
- xor di,di
- mov cx,bp
- shr cx,1
- rep movsw
- adc cx,cx
- rep movsb
-
- mov ah,4 {write plane 2 }
- out dx,ax
- mov si,2*PAGESIZE
- xor di,di
- mov cx,bp
- shr cx,1
- rep movsw
- adc cx,cx
- rep movsb
-
- mov ah,8 {write plane 3 }
- out dx,ax
- mov si,3*PAGESIZE
- xor di,di
- mov cx,bp
- shr cx,1
- rep movsw
- adc cx,cx
- rep movsb
-
- mov ah,1
- out dx,ax
-
- mov al,bl
- cbw {AX:=WinWidth DIV 4; works, because }
- mov dl,LINESIZE
- sub dl,al {DL:=LINESIZE-WinWidth DIV 4}
- jz @region3 {does window run continously from the far left to right?}
- mov dh,bh {DH:=WinHeight-1}
- or dh,dh
- jz @region3 {window height only 1 row?}
- xor ch,ch
- mov bx,ax
- add di,ax
- mov si,di {destination address=starting address due to memory layout}
-
- mov bp,di
- push dx
- @region2a:
- {DL = width of one row of the animation window }
- {DH = WinHeight-1}
- {BX = WinWidth DIV 4 = width of the animation window DIV 4 }
- {CX:=width of one row from the right edge of the animation window to}
- {the left edge of the animation window in the next row: }
- mov cl,dl {ch=0}
- shr cx,1
- rep movsw
- adc cx,cx
- rep movsb
- add si,bx
- add di,bx
- dec dh
- jnz @region2a
-
- mov ax,0202h
- mov dx,3c4h
- out dx,ax
- pop dx
- push dx
- mov si,bp {SI=DI=BP for plane #0, SI=DI+1*PAGESIZE for plane #1, etc.}
- add si,1*PAGESIZE
- mov di,bp
- @region2b:
- mov cl,dl {ch=0}
- shr cx,1
- rep movsw
- adc cx,cx
- rep movsb
- add si,bx
- add di,bx
- dec dh
- jnz @region2b
-
- mov ah,04h
- mov dx,3c4h
- out dx,ax
- pop dx
- push dx
- mov si,bp
- add si,2*PAGESIZE
- mov di,bp
- @region2c:
- mov cl,dl {ch=0}
- shr cx,1
- rep movsw
- adc cx,cx
- rep movsb
- add si,bx
- add di,bx
- dec dh
- jnz @region2c
-
- mov ah,08h
- mov dx,3c4h
- out dx,ax
- pop dx
- mov si,bp
- add si,3*PAGESIZE
- mov di,bp
- @region2d:
- mov cl,dl {ch=0}
- shr cx,1
- rep movsw
- adc cx,cx
- rep movsb
- add si,bx
- add di,bx
- dec dh
- jnz @region2d
-
-
- @region3:
- pop cx {CX:=WinLowerRight}
- jcxz @endregion3 {there is no region 3 to be drawn}
- mov bx,cx {store copy in BX }
- mov si,PAGESIZE
- sub si,cx {starting address of region 3}
- mov di,si {destination address:=starting address (works due to memory layout!)}
- mov bp,di {save destination address }
- mov ax,0102h
- mov dx,3c4h
- out dx,ax
- shr cx,1
- rep movsw
- adc cx,cx
- rep movsb
-
- mov ah,2
- out dx,ax
- mov cx,bx
- mov di,bp
- sub si,cx {reset SI to its old value, then increment it to the next page}
- add si,PAGESIZE
- shr cx,1
- rep movsw
- adc cx,cx
- rep movsb
-
- mov ah,4
- out dx,ax
- mov cx,bx
- mov di,bp
- sub si,cx {reset SI to its old value, then increment it to the next page}
- add si,PAGESIZE
- shr cx,1
- rep movsw
- adc cx,cx
- rep movsb
-
- mov ah,8
- out dx,ax
- mov cx,bx
- mov di,bp
- sub si,cx {reset SI to its old value, then increment it to the next page}
- add si,PAGESIZE
- shr cx,1
- rep movsw
- adc cx,cx
- rep movsb
-
- @endregion3:
- pop bp
- mov ax,seg @data
- mov ds,ax
- dec UpdateOuterArea {reset UpdateOuterArea }
-
- @old_scrolling_bckgnd:
-
- MOV DI,$F {often used constants }
- MOV CX,4
-
- {#tiles, really being cut off at their left edge:}
- {IF StartVirtualX+WinXMIN-BackX1<0}
- { THEN KachelnWegLinks:=(StartVirtualX+WinXMIN-BackX1-15) DIV 16}
- { ELSE KachelnWegLinks:=(StartVirtualX+WinXMIN-BackX1) DIV 16;}
- MOV AX,StartVirtualX
- ADD AX,WinXMIN
- SUB AX,BackX1
- MOV BX,AX {BX = StartVirtualX + WinXMIN - BackX1}
- SAR AX,CL
- MOV KachelnWegLinks,AX
-
- {pixels, which are cut off at the left of the 1st (partially) visible tile: }
- {really: leftcut := ((StartVirtualX + WinXMIN - BackX1) MOD 16) AND $F }
- {but this is equivalent to: }
- {leftcut := (StartVirtualX + WinXMIN - BackX1) AND $F}
- {the "AND $F" is for evtl. underflow <0 }
- AND BX,DI
- MOV leftcut,BX
-
- MOV AX,BX
- SHR AX,1
- SHR AX,1
- MOV leftcutDIV4,AX
-
- {compute 1st read plane of the left-cut tiles: leftcut AND 3 }
- { Then compute the according mask out of this }
- MOV AH,BL {BL = leftcut}
- AND AH,3
- MOV AL,4
- MOV StartLesePlane,AX {must lie in the stack segment!}
-
- {dto., for last (partially) visible tile at the right}
- {really: rightcut := (16 - leftcut - (WinWidth MOD 16)) AND $F, aber s.o.! }
- {rightcut := (16 - leftcut - WinWidth) AND $F}
- {the "AND $F" is for evtl. underflow <0 }
- NEG BX {BX=-leftcut}
- MOV SI,WinWidth
- MOV AX,16
- ADD AX,BX
- SUB AX,SI
- AND AX,DI {AX = (16 - leftcut - WinWidth) AND $F}
- MOV rightcut,AX
-
- {#_non-cut_ tiles in the inner area of the window per row:}
- {innerTilesX:=(WinWidth - (-rightcut AND $F) - (-leftcut AND $F)) SHR 4;}
- NEG AX
- AND AX,DI
- AND BX,DI
- SUB SI,AX
- SUB SI,BX
- SHR SI,CL
- MOV innerTilesX,SI
-
- {stepX1=additonal factor to position from the rightmost (evtl. only partially}
- { visible) tile of one line to the 1st tile of the next row, which }
- { is _not_ cut at its left side}
- {stepX2=dto., but to the 1st (evtl. only partially) visible tile of the }
- { next row }
- {stepX1 := XTiles -(innerTilesX);}
- {stepX2 := stepX1;}
- {IF leftcut<>0 THEN dec(stepX2)} {stepX2 = XTiles -(innerTiles + (leftcut<>0))}
- MOV DX,XTiles
- MOV AX,DX
- SUB AX,SI
- MOV stepX1,AX
- OR BX,BX {for the given range holds: leftcut = 0 <-> -leftcut and $F=0}
- JE @nodec
- DEC AX
- @nodec:
- MOV stepX2,AX
-
-
- {compute 1st write plane of the non-left-cut tiles: }
- { (WinXMIN - leftcut) AND 3, is computed here by }
- { (WinXMIN - (leftcut AND $F) AND 3}
- { Then compute the according mask out of this }
- ADD BX,WinXMIN
- AND BX,3
- MOV AH,CS:[OFFSET CS_TranslateTab +BX]
- MOV AL,2
- MOV StartWritePlane,AX {must lie in the stack segment!}
-
-
- {now the same thing for the Y-direction:}
- {IF StartVirtualY+WinYMIN-BackY1<0}
- { THEN KachelnWegOben := (StartVirtualY + WinYMIN - BackY1 - 15) DIV 16}
- { ELSE KachelnWegOben := (StartVirtualY + WinYMIN - BackY1) DIV 16;}
- MOV AX,StartVirtualY
- ADD AX,WinYMIN
- SUB AX,BackY1
- MOV BX,AX
- SAR AX,CL
- MOV KachelnWegOben,AX
-
- {compute index of 1st (evtl. only partially) visible tile: }
- {actIndex := KachelnWegOben * XTiles + KachelnWegLinks + 1;}
- {The "+1" is to accomodate that the BackTile[]-counting starts at 0}
- {to keep OffscreenTile free! }
- IMUL DX
- ADD AX,KachelnWegLinks
- INC AX
- MOV actIndex,AX
-
- {topcut := (StartVirtualY + WinYMIN - BackY1) AND $F;}
- AND BX,DI
- MOV topcut,BX
-
- {bottomcut := (16 - topcut - WinHeight) AND $F;}
- NEG BX
- MOV SI,WinHeight
- MOV AX,16
- ADD AX,BX
- SUB AX,SI
- AND AX,DI
- MOV bottomcut,AX
-
- {innerTilesY := (WinHeight - (-bottomcut AND $F) - (-topcut AND $F)) SHR 4;}
- NEG AX
- AND AX,DI
- AND BX,DI
- SUB SI,AX
- SUB SI,BX
- SHR SI,CL
- MOV innerTilesY,SI
-
- {---now draw!--- }
-
- { has been set in SetAnimateWindow() already: }
- { MOV AX,WinXMIN}
- { (* MOV x,AX *)}
- { MOV BX,WinYMIN}
- { (* MOV y,BX *)}
- { SHR AX,1}
- { SHR AX,1}
- { MOV WinXMINdiv4,AX}
- { SHL BX,1}
- { MOV BX,CS:[OFFSET GADR +BX]}
- { MOV WinYMIN_mul_LINESIZE,BX}
- { ADD AX,BX}
- { MOV WinYMINmLINESIZEaWinXMINdiv4,AX}
- { }
-
- MOV AX,KachelnWegLinks
- MOV xtil,AX
- MOV CX,AX {CX = copy of KachelnWegLinks = xtil }
- MOV AX,KachelnWegOben
- MOV ytil,AX
-
- MOV ES,PAGEADR {once and for all!}
- MOV BX,leftcut
- {here: AX = ytil, BX = Leftcut, CX = xtil, ES = ^graphic segment }
- TEST BL,3 {leftcut MOD 4 = 0 ?}
- JZ @useMode1 {yes, write mode 1 can be used}
- JMP @useMode0 {no, use write mode 0 }
-
- @useMode1:
- {Go here if width of window is a multiple of 4, leftcut mod 4=0 and the left }
- {edge of the window is a multiple of 4 (this also makes rightcut mod 4=0) }
- {then write mode 1 can be used }
- MOV AX,4105h {enable write mode 1 }
- MOV DX,3CEh
- OUT DX,AX
- MOV AX,0F02h {access all 4 planes at once }
- MOV DX,3C4h
- OUT DX,AX
-
- CMP topcut,0 {IF ytil ε [0..YTiles( }
- JE @m1SkipTopRow { THEN DX = Yoffscreen := $FFFF }
- MOV AX,ytil { ELSE DX = Yoffscreen := $0000 }
- CWD
- SUB AX,YTiles
- NOT AX
- OR AX,DX
- CWD
- NOT DX
- MOV Yoffscreen,DX
-
- MOV AX,WinXMINdiv4 {AX =correct value, if we have to jump! }
- OR BX,BX {BX=leftcut}
- JZ @m1SkipTopLeftCorner
-
- MOV SI,actIndex {IF (xtil < 0) OR (xtil >= XTiles) OR Yoffscreen }
- AND SI,DX { THEN SI := 0 }
- JZ @m1go1 { ELSE SI := actIndex }
- MOV AX,CX {CX = xtil}
- CWD
- SUB AX,XTiles
- NOT AX
- OR AX,DX
- CWD
- NOT DX
- AND SI,DX
-
- @m1go1:
- {PROCEDURE DrawUpperLeftTile with WriteMode1: }
- { in: WinXMIN,WinYMIN = screen coordinates }
- { ES = ^graphic segment}
- { SI = tile index }
- { BX = leftcut }
- { CX = xtil }
- { leftcut MOD 4 = 0 }
- { topcut, Win*, SCROLLADR,...}
- {out: ES = ^graphic segment}
- {rem: WriteMode1 has been set already and remains set }
- MOV AL,[OFFSET BackTile +SI]
- XOR AH,AH {compute offset address of tile: }
- MOV CL,6 {each tile is 64 bytes in size, thus}
- SHL AX,CL {AX := tile * 64 = tile SHL 6 }
-
- MOV SI,topcut {additionaly: the rows cut off at the upper edge:}
- MOV CX,16 {4 bytes for each row }
- SUB CX,SI {CX := 16 - topcut = rows to draw }
- SHL SI,1
- SHL SI,1
- ADD SI,AX {SI = pointer to first tile *row* to copy }
-
- MOV AX,BX {BX = leftcut}
- SHR AX,1 {increment SI by left cut-off = leftcut DIV 4 }
- SHR AX,1
- ADD SI,AX {SI = pointer to first tile *byte* to copy }
-
- MOV DI,WinYMINmLINESIZEaWinXMINdiv4 {ES:DI = destination address}
- MOV DS,SCROLLADR {DS:SI = source address}
- {Now there is no further variable on stack, so BP can be used }
- {for other purposes!}
- PUSH BP {will be needed when leaving the procedure! }
- MOV BP,16 {BP := (16 - leftcut) DIV 4 = bytes per tile row }
- SUB BP,BX
- SHR BP,1
- SHR BP,1
-
- MOV AX,LINESIZE {is a constant }
- SUB AX,BP
- MOV DX,4
- SUB DX,BP
- MOV BX,CX {number of rows }
-
- @m1eineZeile4a1:
- MOV CX,BP
- REP MOVSB
- ADD DI,AX
- ADD SI,DX
- DEC BX
- JNZ @m1eineZeile4a1
-
- POP BP
- MOV AX,SEG @DATA
- MOV DS,AX
-
- {position to next tile to the right of it: }
- INC actIndex
- INC xtil
-
- MOV AX,WinXMIN
- ADD AX,16
- SUB AX,leftcut
- { MOV x,AX }
- SHR AX,1
- SHR AX,1
- @m1SkipTopLeftCorner:
- ADD AX,WinYMIN_mul_LINESIZE
- MOV DI,AX {ES:DI = ^destination address}
-
- {now draw innerTilesX tiles, which are only cut at their top:}
- MOV AX,innerTilesX
- OR AX,AX
- JBE @m1UpperInnerTilesDone
- MOV counter,AX
-
- MOV BX,16 {adjustment factor, to set DI one tile row higher and }
- SUB BX,topcut {one tile column further }
- SHL BX,1
- MOV BX,CS:[OFFSET GADR +BX]
- NEG BX
- ADD BX,4 {BX := -(16 - topcut) * LINESIZE + 4}
-
- @m1repeat1:
- MOV SI,actIndex {IF (xtil < 0) OR (xtil >= XTiles) OR Yoffscreen }
- AND SI,Yoffscreen { THEN SI := 0 }
- JZ @m1go2 { ELSE SI := actIndex }
- MOV AX,xtil
- CWD
- SUB AX,XTiles
- NOT AX
- OR AX,DX
- CWD
- NOT DX
- AND SI,DX
- @m1go2:
- {PROCEDURE DrawUpperInnerTile with WriteMode1: }
- { in: ES:DI = ^destination address}
- { SI = tile index }
- { BX = correction for row}
- { leftcut MOD 4 = 0 }
- { topcut, Win*, SCROLLADR,...}
- {out: ES:DI = ^destination address of the next tile to the right of it}
- {rem: WriteMode1 has been set already and remains set }
- { BX will not be changed }
- MOV AL,[OFFSET BackTile +SI]
- XOR AH,AH {compute offset address of tile: }
- MOV CL,6 {each tile is 64 bytes in size, thus}
- SHL AX,CL {AX := tile * 64 = tile SHL 6 }
-
- MOV SI,topcut {additionaly: the rows cut off at the upper edge:}
- MOV CX,16 {4 bytes for each row }
- SUB CX,SI {CX := 16 - topcut = rows to draw }
- SHL SI,1
- SHL SI,1
- ADD SI,AX {SI = pointer to first tile *row* to copy }
-
- MOV DX,DS
- MOV DS,SCROLLADR
- MOV AX,LINESIZE-4
-
- @m1eineZeile4b1:
- MOVSB
- MOVSB
- MOVSB
- MOVSB
- ADD DI,AX
- LOOP @m1eineZeile4b1
-
- {DI = ^start of the next row below the tile, now position to the next }
- {tile: }
- {┌─┬─┬─┬─┐ ┌─┬─┬─┬─┐▄ }
- {├─┼─┼─┼─┤ ─> ├─┼─┼─┼─┤ }
- {└─┴─┴─┴─┘ └─┴─┴─┴─┘ }
- { ▀ }
- MOV DS,DX {POP BP isn't necessary}
- ADD DI,BX
-
- {position to next tile to the right of it: }
- INC actIndex
- INC xtil
- { MOV AX,16 }
- { ADD x,AX }
- DEC counter
- JNZ @m1repeat1
-
- @m1UpperInnerTilesDone:
- {ES:DI = ^first row of the upper right corner tile}
- CMP rightcut,0
- JE @m1SkipTopRightCorner
-
- MOV SI,actIndex {IF (xtil < 0) OR (xtil >= XTiles) OR Yoffscreen }
- AND SI,Yoffscreen { THEN SI := 0 }
- JZ @m1go3 { ELSE SI := actIndex }
- MOV AX,xtil
- CWD
- SUB AX,XTiles
- NOT AX
- OR AX,DX
- CWD
- NOT DX
- AND SI,DX
- @m1go3:
- {PROCEDURE DrawUpperRightTile with WriteMode1: }
- { in: ES:DI = ^destination address}
- { SI = tile index }
- { rightcut MOD 4 = 0 }
- { topcut, Win*, SCROLLADR,...}
- {out: ES = ^graphic segment }
- {rem: WriteMode1 has been set already and remains set }
- MOV AL,[OFFSET BackTile +SI]
- XOR AH,AH {compute offset address of tile: }
- MOV CL,6 {each tile is 64 bytes in size, thus}
- SHL AX,CL {AX := tile * 64 = tile SHL 6 }
-
- MOV SI,topcut {additionaly: the rows cut off at the upper edge:}
- MOV CX,16 {4 bytes for each row }
- SUB CX,SI {CX := 16 - topcut = rows to draw }
- SHL SI,1
- SHL SI,1
- ADD SI,AX {SI = pointer to first tile *row* to copy }
-
- MOV AX,rightcut
- MOV DS,SCROLLADR {DS:SI = source address}
- {Now there is no further variable on stack, so BP can be used }
- {for other purposes!}
- PUSH BP {will be needed when leaving the procedure! }
- MOV BP,16 {BP := (16 - rightcut) DIV 4 = bytes per tile row }
- SUB BP,AX
- SHR BP,1
- SHR BP,1
-
- MOV AX,LINESIZE
- SUB AX,BP
- MOV DX,4
- SUB DX,BP
- MOV BX,CX {BX := rows to draw }
-
- @m1eineZeile4c1:
- MOV CX,BP
- REP MOVSB
- ADD DI,AX
- ADD SI,DX
- DEC BX
- JNZ @m1eineZeile4c1
-
- POP BP
- MOV AX,SEG @DATA
- MOV DS,AX
-
- @m1SkipTopRightCorner:
- {position on first left tile, which is not cut at its top: }
- MOV AX,stepx2
- ADD actIndex,AX
- { MOV AX,WinXMIN }
- { MOV x,AX }
- MOV AX,KachelnWegLinks
- MOV xtil,AX
- INC ytil
-
- @m1SkipTopRow:
- MOV AX,topcut {IF topcut = 0 }
- NEG AX { THEN AX = y := WinYMIN}
- JZ @m1l1 { ELSE AX = y := WinYMIN + (16 - topcut)}
- ADD AX,16
- @m1l1:
- ADD AX,WinYMIN
- { MOV y,AX }
-
- MOV DI,AX {DI := y * LINESIZE +X DIV 4}
- SHL DI,1
- MOV DI,CS:[OFFSET GADR +DI]
- ADD DI,WinXMINdiv4
- {ES:DI = ^destination address of the 1st tile of the 1st tile row not being cut at its top}
-
- CMP leftcut,0
- JZ @m1SkipLeftColumn
-
- MOV DX,16
- SUB DX,leftcut
- SHR DX,1
- SHR DX,1
- MOV AX,LINESIZE
- SUB AX,DX {correction factor for AX}
- MOV LINESIZE_sub_BytesPerPlane,AX
- MOV BytesPerPlane,DX {bytes to move }
-
- MOV AX,innerTilesY
- OR AX,AX
- JBE @m1LeftLoopDone
- MOV counter,AX
-
- PUSH actIndex
- { PUSH y }
- PUSH ytil
- PUSH DI
-
- MOV AX,xtil
- CWD
- SUB AX,XTiles
- NOT AX
- OR AX,DX
- CWD
- NOT DX
- MOV Xoffscreen,DX {is a constant for the tile column}
- MOV BX,BytesPerPlane
-
- @m1repeat5:
- MOV SI,actIndex
- AND SI,Xoffscreen
- JZ @m1go11
- MOV AX,ytil
- CWD
- SUB AX,YTiles
- NOT AX
- OR AX,DX
- CWD
- NOT DX
- AND SI,DX
- @m1go11:
- {PROCEDURE DrawLeftTile with WriteMode1: }
- { in: ES:DI = ^destination address}
- { SI = tile index }
- { BX = BytesPerPlane }
- { leftcut MOD 4 = 0 }
- { LINESIZE_sub_BytesPerPlane}
- { leftcutDIV4, Win*, SCROLLADR,...}
- {out: ES:DI = ^destination address of the next tile below}
- {rem: WriteMode1 has been set already and remains set }
- { BX will not be changed }
- MOV AL,[OFFSET BackTile +SI]
- XOR AH,AH {compute offset address of tile: }
- MOV CL,6 {each tile is 64 bytes in size, thus}
- SHL AX,CL {AX := tile * 64 = tile SHL 6 }
- MOV SI,AX
-
- ADD SI,leftcutDIV4
- MOV AX,LINESIZE_sub_BytesPerPlane
- MOV DX,4
-
- SUB DX,BX
- MOV DS,SCROLLADR
-
- MOV CX,BX {1.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX {ES:DI = ^next tile }
-
- MOV CX,BX {2.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BX {3.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BX {4.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BX {5.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BX {6.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BX {7.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BX {8.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BX {9.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BX {10.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BX {11.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BX {12.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BX {13.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BX {14.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BX {15.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BX {16.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV AX,SEG @DATA
- MOV DS,AX
-
- {next tile; DI already has the right value}
- MOV AX,XTiles
- ADD actIndex,AX
- { MOV AX,16 }
- { ADD y,AX }
- INC ytil
-
- DEC counter
- JNZ @m1repeat5
-
- POP DI
- POP ytil
- { POP y }
- POP actIndex
-
- @m1LeftLoopDone:
- INC actIndex
- ADD DI,BytesPerPlane
- INC xtil
- { MOV AX,16 }
- { SUB AX,leftcut }
- { ADD x,AX }
-
- @m1SkipLeftColumn:
- {ES:DI = ^destination address of the first inner tile (still)}
-
- MOV AX,innerTilesY {are there any inner tiles at all?}
- OR AX,AX
- JBE @m1SkipInnerTiles
- CMP innerTilesX,0
- JB @m1SkipInnerTiles
-
- MOV counter,AX
- MOV AX,actIndex {make copies of the actual values }
- MOV tempActIndex,AX
- { MOV AX,x }
- { MOV tempX,AX }
- MOV AX,xtil
- MOV tempXtil,AX
- { MOV AX,y }
- { MOV tempY,AX }
- MOV AX,ytil
- MOV tempYtil,AX
- MOV tempDI,DI
-
- CMP rightcut,0
- JE @m1SkipRightColumn
-
- MOV DX,16
- SUB DX,rightcut
- SHR DX,1
- SHR DX,1
- MOV BytesPerPlane,DX
- MOV AX,LINESIZE
- SUB AX,DX
- MOV LINESIZE_sub_BytesPerPlane,AX
-
- MOV AX,innerTilesX
- ADD xtil,AX
- ADD actIndex,AX
- MOV CL,2
- SHL AX,CL
- ADD DI,AX {ES:DI = ^first right edge-tile which is not cut at its top }
- { SHL AX,CL }
- { ADD x,AX }
-
- MOV AX,xtil
- CWD
- SUB AX,XTiles
- NOT AX
- OR AX,DX
- CWD
- NOT DX
- MOV Xoffscreen,DX
- MOV BX,BytesPerPlane
-
- @m1repeat6:
- MOV SI,actIndex
- AND SI,Xoffscreen
- JZ @m1go12
- MOV AX,ytil
- CWD
- SUB AX,YTiles
- NOT AX
- OR AX,DX
- CWD
- NOT DX
- AND SI,DX
- @m1go12:
- {PROCEDURE DrawRightTile with WriteMode1: }
- { in: ES:DI = ^destination address}
- { SI = tile index }
- { BX = BytesPerPlane }
- { rightcut MOD 4 = 0 }
- { innerTilesY >= 1 }
- { LINESIZE_sub_BytesPerPlane}
- { SCROLLADR,...}
- {out: ES:DI = ^destination address of the next tile below}
- {rem: WriteMode1 has been set already and remains set }
- { BX will not be changed }
- MOV AL,[OFFSET BackTile +SI]
- XOR AH,AH {compute offset address of tile: }
- MOV CL,6 {each tile is 64 bytes in size, thus}
- SHL AX,CL {AX := tile * 64 = tile SHL 6 }
- MOV SI,AX
-
- MOV AX,LINESIZE_sub_BytesPerPlane
- MOV DX,4
-
- SUB DX,BX
- MOV DS,SCROLLADR
-
- MOV CX,BX {1.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX {ES:DI = ^next tile }
-
- MOV CX,BX {2.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BX {3.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BX {4.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BX {5.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BX {6.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BX {7.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BX {8.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BX {9.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BX {10.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BX {11.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BX {12.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BX {13.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BX {14.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BX {15.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BX {16.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV AX,SEG @DATA
- MOV DS,AX
-
- {next tile; DI already has the right value}
- MOV AX,XTiles
- ADD actIndex,AX
- { MOV AX,16 }
- { ADD y,AX }
- INC ytil
-
- DEC counter
- JNZ @m1repeat6
-
- MOV DI,tempDI
- MOV AX,tempActIndex
- MOV actIndex,AX
- { MOV AX,tempX }
- { MOV x,tempX }
- MOV AX,tempXtil
- MOV xtil,AX
- { MOV AX,tempY }
- { MOV y,AX }
- MOV AX,tempYtil
- MOV ytil,AX
-
- @m1RightLoopDone:
- @m1SkipRightColumn:
- {ES:DI = ^destination address of the first inner tile (still)}
- {innerTilesX >= 0, innerTilesX >= 1 -> it would suffice to check innerTilesX=0:}
-
- CMP innerTilesX,0 {IF (innerTilesX <= 0) OR (innerTilesY <= 0) THEN skip}
- JBE @m1SkipInnerTiles {If there are no inner tiles, then the }
- {actual position is located at the 1st tile which }
- {is not cut at its left and is in the lowest tile row }
-
-
- {now "FOR x:=1 TO innerTilesX DO FOR y:=1 TO innerTilesY DO .." }
- MOV oldDI,DI {make temporary copies of DI and actIndex }
- MOV BX,actIndex {BX corresponds to "oldActIndex"}
-
- MOV AX,innerTilesX
- MOV counter,AX {counter for X-direction}
- MOV CL,6
-
- @m1xloop:
- MOV AX,xtil
- CWD
- SUB AX,XTiles
- NOT AX
- OR AX,DX
- CWD
- NOT DX
- MOV Xoffscreen,DX {is a constant for the tile column}
-
- MOV AX,innerTilesY
- MOV CH,AL {CH is used as a counter for the Y-direction}
-
-
- @m1yloop:
- MOV SI,BX {SI = temp. actIndex}
- AND SI,Xoffscreen
- JZ @m1go5
- MOV AX,ytil
- CWD
- SUB AX,YTiles
- NOT AX
- OR AX,DX
- CWD
- NOT DX
- AND SI,DX
- @m1go5:
- {PROCEDURE DrawInnerTile with WriteMode1: }
- { in: ES:DI = ^destination address}
- { SI = tile index }
- { CL = 6 }
- { SCROLLADR}
- {out: ES:DI = ^destination address of the next tile below}
- { CL = 6}
- {rem: WriteMode1 has been set already and remains set }
- { CH, BX may not be changed! }
- MOV AL,[OFFSET BackTile +SI]
- XOR AH,AH {compute offset address of tile: }
- {each tile is 64 bytes in size, thus}
- SHL AX,CL {AX := tile * 64 = tile SHL 6 }
- MOV SI,AX
-
- MOV DX,DS {save DS to DX }
- MOV DS,SCROLLADR
-
- MOVSB {1.row }
- MOVSB
- MOVSB
- MOVSB
- ADD DI,LINESIZE-4 {ES:DI = ^next tile }
-
- MOVSB {2.row }
- MOVSB
- MOVSB
- MOVSB
- ADD DI,LINESIZE-4
-
- MOVSB {3.row }
- MOVSB
- MOVSB
- MOVSB
- ADD DI,LINESIZE-4
-
- MOVSB {4.row }
- MOVSB
- MOVSB
- MOVSB
- ADD DI,LINESIZE-4
-
- MOVSB {5.row }
- MOVSB
- MOVSB
- MOVSB
- ADD DI,LINESIZE-4
-
- MOVSB {6.row }
- MOVSB
- MOVSB
- MOVSB
- ADD DI,LINESIZE-4
-
- MOVSB {7.row }
- MOVSB
- MOVSB
- MOVSB
- ADD DI,LINESIZE-4
-
- MOVSB {8.row }
- MOVSB
- MOVSB
- MOVSB
- ADD DI,LINESIZE-4
-
- MOVSB {9.row }
- MOVSB
- MOVSB
- MOVSB
- ADD DI,LINESIZE-4
-
- MOVSB {10.row }
- MOVSB
- MOVSB
- MOVSB
- ADD DI,LINESIZE-4
-
- MOVSB {11.row }
- MOVSB
- MOVSB
- MOVSB
- ADD DI,LINESIZE-4
-
- MOVSB {12.row }
- MOVSB
- MOVSB
- MOVSB
- ADD DI,LINESIZE-4
-
- MOVSB {13.row }
- MOVSB
- MOVSB
- MOVSB
- ADD DI,LINESIZE-4
-
- MOVSB {14.row }
- MOVSB
- MOVSB
- MOVSB
- ADD DI,LINESIZE-4
-
- MOVSB {15.row }
- MOVSB
- MOVSB
- MOVSB
- ADD DI,LINESIZE-4
-
- MOVSB {16.row }
- MOVSB
- MOVSB
- MOVSB
- ADD DI,LINESIZE-4
-
-
- MOV DS,DX
-
- {next tile; DI already has the right value}
- ADD BX,XTiles {set temp. actIndex to next row }
- INC ytil
- { MOV AX,16 }
- { ADD y,AX }
-
- DEC CH
- JNZ @m1yloop
-
- {actIndex still has its old value as only "oldActIndex" has been changed }
- INC actIndex {actIndex = next inner tile in uppermost tile row }
- MOV BX,actIndex {and use it as starting value for next column }
-
- MOV DI,oldDI {ES:DI = ^inner tile in uppermost tile row }
- ADD DI,4 {increment by one tile }
- MOV oldDI,DI {and use it as starting value for next column }
-
- MOV AX,tempYtil
- MOV ytil,AX {set Y-coordinate back to the uppermost inner tile row }
- { MOV AX,oldY }
- { MOV y,AX }
-
- INC xtil {increment X-coordinate by one tile column }
- { MOV AX,16 }
- { ADD x,AX }
-
- DEC counter
- JNZ @m1xloop
-
- MOV DI,tempDI {Thus: ES:DI, actIndex, xtil, ytil, x, y point to }
- MOV AX,tempActIndex {the first inner tile again (N.B.: y, ytil have }
- MOV actIndex,AX {restored some lines above, already! }
- MOV AX,tempXtil
- MOV xtil,AX
- { MOV AX,tempX }
- { MOV x,AX }
-
- MOV AX,innerTilesY
- MOV DX,AX {hold a copy in DX }
- ADD ytil,AX {ytil points to the bottommost tile row }
-
- MOV CL,5
- SHL AX,CL {dto. for DI: inc(DI,16 * innerTilesY * LINESIZE) }
- MOV BX,AX
- ADD DI,CS:[OFFSET GADR +BX]
- { SHR AX,1 }
- { ADD y,AX } {dto. for y: inc(y,16 * innerTilesY) }
-
- MOV AX,XTiles
- MUL DX {AX := XTiles * innerTilesY}
- ADD actIndex,AX {dto. for actIndex: inc(actIndex,XTiles * innerTilesY) }
-
- @m1SkipInnerTiles:
- {ES:DI, actIndex, xtil, ytil, x, y point to the first inner tile of the}
- {bottommost tile row }
- CMP bottomcut,0
- JE @m1fertig
-
- MOV AX,ytil
- CWD
- SUB AX,YTiles
- NOT AX
- OR AX,DX
- CWD
- NOT DX
- MOV Yoffscreen,DX
-
- MOV AX,innerTilesX
- OR AX,AX
- JBE @m1LowerInnerTilesDone {are we standing at the right bottom corner tile? }
- MOV counter,AX
-
- {compute addition factor needed to position from bottom to top:}
- {┌─┬─┬─┬─┐ ┌─┬─┬─┬─┐▄ }
- {├─┼─┼─┼─┤ ─> ├─┼─┼─┼─┤ }
- {└─┴─┴─┴─┘ └─┴─┴─┴─┘ }
- { ▀ }
- {BX := -(16 - bottomcut) * LINESIZE + 4}
- MOV BX,16
- SUB BX,bottomcut
- SHL BX,1
- MOV BX,CS:[OFFSET GADR +BX]
- NEG BX
- ADD BX,4
-
- @m1repeat4:
- MOV SI,actIndex
- AND SI,Yoffscreen
- JZ @m1go8
-
- MOV AX,xtil
- CWD
- SUB AX,XTiles
- NOT AX
- OR AX,DX
- CWD
- NOT DX
- AND SI,DX
- @m1go8:
- {PROCEDURE DrawLowerInnerTile with WriteMode1: }
- { in: ES:DI = ^destination address}
- { SI = tile index }
- { BX = adjustment for row addresses }
- { bottomcut, Win*, SCROLLADR,...}
- {out: ES:DI = ^destination address of the next tile to the right of it}
- { BX = adjustment for row addresses }
- {rem: WriteMode1 has been set already and remains set }
- { DX is not used }
- MOV AL,[OFFSET BackTile +SI]
- XOR AH,AH {compute offset address of tile: }
- MOV CL,6 {each tile is 64 bytes in size, thus}
- SHL AX,CL {AX := tile * 64 = tile SHL 6 }
- MOV SI,AX
-
- MOV CX,16
- SUB CX,bottomcut
-
- MOV AX,DS {save DS to AX }
- MOV DS,SCROLLADR
-
- @m1eineZeile4e1:
- MOVSB
- MOVSB
- MOVSB
- MOVSB
- ADD DI,LINESIZE-4
- LOOP @m1eineZeile4e1
-
- MOV DS,AX
-
- {DI = ^start of the next row below the tile, now position to the next }
- {tile: }
- {┌─┬─┬─┬─┐ ┌─┬─┬─┬─┐▄ }
- {├─┼─┼─┼─┤ ─> ├─┼─┼─┼─┤ }
- {└─┴─┴─┴─┘ └─┴─┴─┴─┘ }
- { ▀ }
- ADD DI,BX
-
- {position to next tile to the right of it: }
- INC actIndex
- INC xtil
- { MOV AX,16 }
- { ADD x,AX }
-
- DEC counter
- JNZ @m1repeat4
-
- @m1LowerInnerTilesDone:
- {ES:DI, actIndex, xtil, ytil, x, y point to the lower right corner tile}
- CMP rightcut,0
- JE @m1SkipLowerRightCorner
-
- PUSH DI
- MOV SI,actIndex
- AND SI,Yoffscreen
- JZ @m1go9
- MOV AX,xtil
- CWD
- SUB AX,XTiles
- NOT AX
- OR AX,DX
- CWD
- NOT DX
- AND SI,DX
- @m1go9:
- {PROCEDURE DrawLowerRightTile with WriteMode1: }
- { in: ES:DI = ^destination address}
- { SI = tile index }
- { rightcut MOD 4 = 0 }
- { rightcut, bottomcut, Win*, SCROLLADR,...}
- {out: ES = ^graphic segment }
- {rem: WriteMode1 has been set already and remains set }
- MOV AL,[OFFSET BackTile +SI]
- XOR AH,AH {compute offset address of tile: }
- MOV CL,6 {each tile is 64 bytes in size, thus}
- SHL AX,CL {AX := tile * 64 = tile SHL 6 }
- MOV SI,AX
-
- MOV CX,16
- SUB CX,bottomcut
- MOV BX,16
- SUB BX,rightcut
- SHR BX,1
- SHR BX,1 {BX = BytesPerPlane = (16 - rightcut) DIV 4}
-
- MOV DS,SCROLLADR
-
- MOV AX,LINESIZE
- SUB AX,BX
- MOV DX,4
- SUB DX,BX
- PUSH BP
- MOV BP,CX {BP=row counter }
-
- @m1eineZeile4g1:
- MOV CX,BX
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
- DEC BP
- JNZ @m1eineZeile4g1
-
- POP BP
- MOV AX,SEG @DATA
- MOV DS,AX
-
- POP DI {ES:DI etc. point to lower right corner tile }
-
- @m1SkipLowerRightCorner:
- CMP leftcut,0
- JE @m1fertig
-
- {now position on lower left corner tile: }
- MOV AX,innerTilesX
- INC AX
- SUB actIndex,AX {dec(actIndex,innerTilesX + 1) }
- SUB xtil,AX {dec(xtil,innerTilesX + 1) }
- MOV CL,2
- SHL AX,CL
- SUB DI,AX {dec(DI,4 * (innerTilesX + 1) }
- ADD DI,leftcutDIV4 {don't forget: corner tile may be cut at its left side}
- { MOV AX,WinXMIN }
- { MOV x,AX }
-
- MOV SI,actIndex
- AND SI,Yoffscreen
- JZ @m1go7
- MOV AX,xtil
- CWD
- SUB AX,XTiles
- NOT AX
- OR AX,DX
- CWD
- NOT DX
- AND SI,DX
- @m1go7:
- {PROCEDURE DrawLowerLeftTile with WriteMode1: }
- { in: ES:DI = ^destination address}
- { SI = tile index }
- { rightcut MOD 4 = 0 }
- { leftcut, bottomcut, Win*, SCROLLADR,...}
- {out: (ES = ^graphic segment) }
- {rem: WriteMode1 has been set (and remains set) }
- MOV AL,[OFFSET BackTile +SI]
- XOR AH,AH {compute offset address of tile: }
- MOV CL,6 {each tile is 64 bytes in size, thus}
- SHL AX,CL {AX := tile * 64 = tile SHL 6 }
- MOV SI,AX
-
- MOV AX,leftcut
- MOV BX,AX
- MOV CL,2
- SHR AX,CL
- ADD SI,AX
-
- MOV CX,16
- SUB CX,bottomcut
-
- MOV DS,SCROLLADR
-
- PUSH BP
- MOV BP,16
- SUB BP,BX
- SHR BP,1
- SHR BP,1 {BP:=(16 - leftcut) DIV 4}
-
- MOV AX,LINESIZE
- SUB AX,BP
- MOV DX,4
- SUB DX,BP
-
- MOV BX,CX {BX = row counter }
-
- @m1eineZeile4d1:
- MOV CX,BP
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
- DEC BX
- JNZ @m1eineZeile4d1
-
- POP BP
- MOV AX,SEG @DATA
- MOV DS,AX
-
- @m1fertig:
- {now switch back to write mode 0: }
- MOV AX,4005h
- MOV DX,3CEh
- OUT DX,AX
- JMP @Sprites_zeichnen
-
- {----------------------------------------------------}
-
- @useMode0:
- CMP topcut,0 {IF ytil ε [0..YTiles( }
- JE @m0SkipTopRow { THEN DX = Yoffscreen := $FFFF }
- MOV AX,ytil { ELSE DX = Yoffscreen := $0000 }
- CWD
- SUB AX,YTiles
- NOT AX
- OR AX,DX
- CWD
- NOT DX
- MOV Yoffscreen,DX
-
- MOV AX,WinXMINdiv4 {AX = correct value, if we have to jump! }
- OR BX,BX {BX=leftcut}
- JZ @m0SkipTopLeftCorner
-
- MOV SI,actIndex {IF (xtil < 0) OR (xtil >= XTiles) OR Yoffscreen }
- AND SI,DX { THEN SI := 0 }
- JZ @m0go1 { ELSE SI := actIndex }
- MOV AX,CX {CX = xtil}
- CWD
- SUB AX,XTiles
- NOT AX
- OR AX,DX
- CWD
- NOT DX
- AND SI,DX
-
- @m0go1:
- {PROCEDURE DrawUpperLeftTile with WriteMode0: }
- { in: WinXMIN,WinYMIN = screen coordinates }
- { ES = ^graphic segment}
- { SI = tile index }
- { BX = leftcut }
- { CX = xtil }
- { topcut, Win*, SCROLLADR,...}
- {out: ES = ^graphic segment}
- {rem: WriteMode0 has been set already and remains set }
- MOV AL,[OFFSET BackTile +SI]
- XOR AH,AH {compute offset address of tile: }
- MOV CL,6 {each tile is 64 bytes in size, thus}
- SHL AX,CL {AX := tile * 64 = tile SHL 6 }
-
- MOV SI,topcut {additionaly: the rows cut off at the upper edge:}
- MOV CX,16 {4 bytes for each row }
- SUB CX,SI {CX := 16 - topcut = rows to draw }
- SHL SI,1
- SHL SI,1
- ADD SI,AX {SI = pointer to first tile *row* to copy }
-
- MOV AX,BX {BX = leftcut}
- SHR AX,1 {increment SI by left cut-off = leftcut DIV 4 }
- SHR AX,1
- ADD SI,AX {SI = pointer to first tile *byte* to copy }
-
- MOV DI,WinYMINmLINESIZEaWinXMINdiv4 {ES:DI = destination address}
- MOV DS,SCROLLADR {DS:SI = source address}
- {Now there is no further variable on stack, so BP can be used }
- {for other purposes!}
- PUSH BP {will be needed when leaving the procedure! }
- MOV BP,16+3 {BP:=(16 + 3 - leftcut) DIV 4 = bytes per tile row }
- SUB BP,BX
- PUSH BP {save BP for next plane }
- SHR BP,1
- SHR BP,1
-
- MOV AH,BL {BL = leftcut}
- AND AH,3
- MOV AL,4
- MOV DX,3CEh
- OUT DX,AX {select first read plane}
- PUSH AX
- MOV DX,3C4h
- MOV AX,0102h
- OUT DX,AX {choose write plane 0 }
-
- MOV AX,LINESIZE {is a constant }
- SUB AX,BP
- MOV DX,4
- SUB DX,BP
- MOV BX,CX {number of rows }
-
- PUSH SI
- PUSH DI
- PUSH BX
- @m0eineZeile4a1:
- MOV CX,BP
- REP MOVSB
- ADD DI,AX
- ADD SI,DX
- DEC BX
- JNZ @m0eineZeile4a1
- POP BX
- POP DI
- POP SI
-
- MOV DX,3C4h
- MOV AX,0202h
- OUT DX,AX {choose write plane 1 }
- MOV DX,3CEh
- POP AX
- INC AH
- AND AH,3
- JNE @nowrap1a
- INC SI
- @nowrap1a:
- OUT DX,AX {select next read plane }
- POP BP {BP = 16 + 3 - leftcut }
- DEC BP
- PUSH BP
- PUSH AX
- SHR BP,1
- SHR BP,1
-
- MOV AX,LINESIZE {is a constant }
- SUB AX,BP
- MOV DX,4
- SUB DX,BP
-
- PUSH SI
- PUSH DI
- PUSH BX
- @m0eineZeile4a2:
- MOV CX,BP
- REP MOVSB
- ADD DI,AX
- ADD SI,DX
- DEC BX
- JNZ @m0eineZeile4a2
- POP BX
- POP DI
- POP SI
-
- MOV DX,3C4h
- MOV AX,0402h
- OUT DX,AX {choose write plane 2 }
- MOV DX,3CEh
- POP AX
- INC AH
- AND AH,3
- JNE @nowrap2a
- INC SI
- @nowrap2a:
- OUT DX,AX {select next read plane }
- POP BP {BP = 16 + 2 - leftcut }
- DEC BP
- PUSH BP
- PUSH AX
- SHR BP,1
- SHR BP,1
-
- MOV AX,LINESIZE {is a constant }
- SUB AX,BP
- MOV DX,4
- SUB DX,BP
-
- PUSH SI
- PUSH DI
- PUSH BX
- @m0eineZeile4a3:
- MOV CX,BP
- REP MOVSB
- ADD DI,AX
- ADD SI,DX
- DEC BX
- JNZ @m0eineZeile4a3
- POP BX
- POP DI
- POP SI
-
- MOV DX,3C4h
- MOV AX,0802h
- OUT DX,AX {choose write plane 3 }
- MOV DX,3CEh
- POP AX
- INC AH
- AND AH,3
- JNE @nowrap3a
- INC SI
- @nowrap3a:
- OUT DX,AX {select next read plane }
- POP BP {BP = 16+ 1 - leftcut }
- DEC BP
-
-
- SHR BP,1
- SHR BP,1
-
- MOV AX,LINESIZE {is a constant }
- SUB AX,BP
- MOV DX,4
- SUB DX,BP
-
- @m0eineZeile4a4:
- MOV CX,BP
- REP MOVSB
- ADD DI,AX
- ADD SI,DX
- DEC BX
- JNZ @m0eineZeile4a4
-
- POP BP
- MOV AX,SEG @DATA
- MOV DS,AX
-
- {position to next tile to the right of it: }
- INC actIndex
- INC xtil
-
- MOV AX,WinXMIN
- ADD AX,16
- SUB AX,leftcut
- { MOV x,AX }
- SHR AX,1
- SHR AX,1
- @m0SkipTopLeftCorner:
- ADD AX,WinYMIN_mul_LINESIZE
- MOV DI,AX {ES:DI = ^destination address}
-
- {now draw innerTilesX tiles, which are only cut at their top:}
- MOV AX,innerTilesX
- OR AX,AX
- JBE @m0UpperInnerTilesDone
- MOV counter,AX
-
- MOV BX,16 {correction factor to set DI one tile row higher and one}
- SUB BX,topcut {one tile column further }
- SHL BX,1
- MOV AX,CS:[OFFSET GADR +BX]
- NEG AX
- ADD AX,4
- MOV Korrektur,AX {Korrektur := -(16 - topcut) * LINESIZE + 4}
-
- @m0repeat1:
- MOV SI,actIndex {IF (xtil < 0) OR (xtil >= XTiles) OR Yoffscreen }
- AND SI,Yoffscreen { THEN SI := 0 }
- JZ @m0go2 { ELSE SI := actIndex }
- MOV AX,xtil
- CWD
- SUB AX,XTiles
- NOT AX
- OR AX,DX
- CWD
- NOT DX
- AND SI,DX
- @m0go2:
- {PROCEDURE DrawUpperInnerTile with WriteMode0: }
- { in: ES:DI = ^destination address}
- { SI = tile index }
- { topcut, Win*, SCROLLADR,...}
- {out: ES:DI = ^destination address of the next tile to the right of it}
- {rem: WriteMode0 has been set already and remains set }
- MOV AL,[OFFSET BackTile +SI]
- XOR AH,AH {compute offset address of tile: }
- MOV CL,6 {each tile is 64 bytes in size, thus}
- SHL AX,CL {AX := tile * 64 = tile SHL 6 }
-
- MOV SI,topcut {additionaly: the rows cut off at the upper edge:}
- MOV CX,16 {4 bytes for each row }
- SUB CX,SI {CX := 16 - topcut = rows to draw }
- SHL SI,1
- SHL SI,1
- ADD SI,AX {SI = pointer to first tile *row* to copy }
-
- PUSH BP {save BP }
- MOV DX,3C4h
- MOV AX,StartWritePlane
- OUT DX,AX {select first write plane }
- PUSH AX
- MOV DX,3CEh
- MOV AX,0004h
- OUT DX,AX {choose read plane 0}
-
- MOV DS,SCROLLADR {now unused: AX, BX, BP, DX}
-
- MOV BX,CX {copy of row counter}
- MOV BP,SI {BP = copy of SI }
- MOV AX,DI {AX = copy of DI }
- @m0eineZeile4b1:
- MOVSW
- MOVSW
- ADD DI,LINESIZE-4
- LOOP @m0eineZeile4b1
- MOV SI,BP {restore old values }
- MOV DI,AX
- MOV CX,BX
-
- MOV AX,0104h
- OUT DX,AX {DX = 3CEh -> choose read plane 1}
- MOV DX,3C4h
- POP AX
- SHL AH,1
- CMP AH,16
- JNE @nowrap1b
- MOV AH,1
- INC DI
- @nowrap1b:
- OUT DX,AX {select next write plane }
- PUSH AX
- MOV AX,DI
-
- @m0eineZeile4b2:
- MOVSW
- MOVSW
- ADD DI,LINESIZE-4
- LOOP @m0eineZeile4b2
- MOV SI,BP {restore old values }
- MOV DI,AX
- MOV CX,BX
-
- POP AX
- SHL AH,1
- CMP AH,16
- JNE @nowrap2b
- MOV AH,1
- INC DI
- @nowrap2b:
- OUT DX,AX {DX = 3C4h -> select next write plane }
- PUSH AX
- MOV DX,3CEh
- MOV AX,0204h
- OUT DX,AX {choose read plane 2}
- MOV AX,DI
-
- @m0eineZeile4b3:
- MOVSW
- MOVSW
- ADD DI,LINESIZE-4
- LOOP @m0eineZeile4b3
- MOV SI,BP {restore old values }
- MOV DI,AX
- MOV CX,BX
-
- MOV AX,0304h
- OUT DX,AX {DX = 3CEh -> choose read plane 3}
- MOV DX,3C4h
- POP AX
- SHL AH,1
- CMP AH,16
- JNE @nowrap3b
- MOV AH,1
- INC DI
- @nowrap3b:
- OUT DX,AX {select last write plane: no more PUSHs necessary}
-
- @m0eineZeile4b4:
- MOVSW
- MOVSW
- ADD DI,LINESIZE-4
- LOOP @m0eineZeile4b4
- {don't restore old values }
-
- POP BP {make TP happy }
- MOV AX,SEG @Data
- MOV DS,AX
-
- {DI = ^start of the next row below the tile, now position to the next }
- {tile: }
- {┌─┬─┬─┬─┐ ┌─┬─┬─┬─┐▄ }
- {├─┼─┼─┼─┤ ─> ├─┼─┼─┼─┤ }
- {└─┴─┴─┴─┘ └─┴─┴─┴─┘ }
- { ▀ }
- ADD DI,Korrektur
- {-1, because "inc di" has been executed exactly 1x}
- DEC DI
-
- {position to next tile to the right of it: }
- INC actIndex
- INC xtil
- { MOV AX,16 }
- { ADD x,AX }
- DEC counter
- JNZ @m0repeat1
-
- @m0UpperInnerTilesDone:
- {ES:DI = ^first row of the upper right corner tile}
- CMP rightcut,0
- JE @m0SkipTopRightCorner
-
- MOV SI,actIndex {IF (xtil < 0) OR (xtil >= XTiles) OR Yoffscreen }
- AND SI,Yoffscreen { THEN SI := 0 }
- JZ @m0go3 { ELSE SI := actIndex }
- MOV AX,xtil
- CWD
- SUB AX,XTiles
- NOT AX
- OR AX,DX
- CWD
- NOT DX
- AND SI,DX
- @m0go3:
- {PROCEDURE DrawUpperRightTile with WriteMode0: }
- { in: ES:DI = ^destination address}
- { SI = tile index }
- { StartWritePlane = first bitplane to write to }
- { topcut, rightcut, Win*, SCROLLADR,...}
- {out: ES = ^graphic segment }
- {rem: WriteMode0 has been set already and remains set }
- MOV AL,[OFFSET BackTile +SI]
- XOR AH,AH {compute offset address of tile: }
- MOV CL,6 {each tile is 64 bytes in size, thus}
- SHL AX,CL {AX := tile * 64 = tile SHL 6 }
-
- MOV SI,topcut {additionaly: the rows cut off at the upper edge:}
- MOV CX,16 {4 bytes for each row }
- SUB CX,SI {CX := 16 - topcut = rows to draw }
- SHL SI,1
- SHL SI,1
- ADD SI,AX {SI = pointer to first tile *row* to copy }
-
- MOV BX,rightcut
- PUSH BP {will be needed when leaving the procedure! }
- MOV DS,SCROLLADR {DS:SI = source address}
- MOV DX,3C4h
- MOV AX,StartWritePlane
- OUT DX,AX
- PUSH AX
- MOV DX,3CEh
- MOV AX,0004h
- OUT DX,AX
- {Now there is no further variable on stack, so BP can be used }
- {for other purposes!}
- MOV BP,16+3 {BP:=(16 + 3 - rightcut) DIV 4 = bytes per tile row }
- SUB BP,BX
- PUSH BP
- SHR BP,1
- SHR BP,1
-
- MOV AX,LINESIZE
- SUB AX,BP
- MOV DX,4
- SUB DX,BP
- MOV BX,CX {BX := rows to draw }
-
- PUSH BX
- PUSH SI
- PUSH DI
- @m0eineZeile4c1:
- MOV CX,BP
- REP MOVSB
- ADD DI,AX
- ADD SI,DX
- DEC BX
- JNZ @m0eineZeile4c1
- POP DI
- POP SI
- POP BX
- POP BP
- POP AX
-
- SHL AH,1
- CMP AH,16
- JNE @nowrap1c
- MOV AH,1
- INC DI
- @nowrap1c:
- MOV DX,3C4h
- OUT DX,AX
- PUSH AX
- MOV DX,3CEh
- MOV AX,0104h
- OUT DX,AX
-
- DEC BP {BP := 16 + 2 - rightcut}
- PUSH BP
- SHR BP,1
- SHR BP,1
- MOV AX,LINESIZE
- SUB AX,BP
- MOV DX,4
- SUB DX,BP
-
- PUSH BX
- PUSH SI
- PUSH DI
- @m0eineZeile4c2:
- MOV CX,BP
- REP MOVSB
- ADD DI,AX
- ADD SI,DX
- DEC BX
- JNZ @m0eineZeile4c2
- POP DI
- POP SI
- POP BX
- POP BP
- POP AX
-
- SHL AH,1
- CMP AH,16
- JNE @nowrap2c
- MOV AH,1
- INC DI
- @nowrap2c:
- MOV DX,3C4h
- OUT DX,AX
- PUSH AX
- MOV DX,3CEh
- MOV AX,0204h
- OUT DX,AX
-
- DEC BP {BP := 16 + 1 - rightcut}
- PUSH BP
- SHR BP,1
- SHR BP,1
- MOV AX,LINESIZE
- SUB AX,BP
- MOV DX,4
- SUB DX,BP
-
- PUSH BX
- PUSH SI
- PUSH DI
- @m0eineZeile4c3:
- MOV CX,BP
- REP MOVSB
- ADD DI,AX
- ADD SI,DX
- DEC BX
- JNZ @m0eineZeile4c3
- POP DI
- POP SI
- POP BX
- POP BP
- POP AX
-
- SHL AH,1
- CMP AH,16
- JNE @nowrap3c
- MOV AH,1
- INC DI
- @nowrap3c:
- MOV DX,3C4h
- OUT DX,AX
-
- MOV DX,3CEh
- MOV AX,0304h
- OUT DX,AX
-
- DEC BP {BP := 16 + 0 - rightcut}
-
- SHR BP,1
- SHR BP,1
- MOV AX,LINESIZE
- SUB AX,BP
- MOV DX,4
- SUB DX,BP
-
- @m0eineZeile4c4:
- MOV CX,BP
- REP MOVSB
- ADD DI,AX
- ADD SI,DX
- DEC BX
- JNZ @m0eineZeile4c4
-
-
- POP BP
- MOV AX,SEG @DATA
- MOV DS,AX
-
- @m0SkipTopRightCorner:
- {position on first left tile, which is not cut at its top: }
- MOV AX,stepx2
- ADD actIndex,AX
- { MOV AX,WinXMIN }
- { MOV x,AX }
- MOV AX,KachelnWegLinks
- MOV xtil,AX
- INC ytil
-
- @m0SkipTopRow:
- MOV AX,topcut {IF topcut = 0 }
- NEG AX { THEN AX = y := WinYMIN}
- JZ @m0l1 { ELSE AX = y := WinYMIN + (16 - topcut)}
- ADD AX,16
- @m0l1:
- ADD AX,WinYMIN
- { MOV y,AX }
-
- MOV DI,AX {DI := y * LINESIZE +X DIV 4}
- SHL DI,1
- MOV DI,CS:[OFFSET GADR +DI]
- ADD DI,WinXMINdiv4
- {ES:DI = ^destination address of the 1st tile of the 1st tile row not being cut at its top}
-
- CMP leftcut,0
- JZ @m0SkipLeftColumn
-
- MOV DX,16+3
- SUB DX,leftcut
- SHR DX,1
- SHR DX,1
- MOV AX,LINESIZE
- SUB AX,DX {correction factor for AX}
- MOV LINESIZE_sub_BytesPerPlane,AX
- MOV BytesPerPlane,DX {bytes to move }
-
- MOV AX,innerTilesY
- OR AX,AX
- JBE @m0LeftLoopDone
- MOV counter,AX
-
- PUSH actIndex
- { PUSH y }
- PUSH ytil
- PUSH DI
-
- MOV AX,xtil
- CWD
- SUB AX,XTiles
- NOT AX
- OR AX,DX
- CWD
- NOT DX
- MOV Xoffscreen,DX {is a constant for the tile column}
-
- @m0repeat5:
- MOV SI,actIndex
- AND SI,Xoffscreen
- JZ @m0go11
- MOV AX,ytil
- CWD
- SUB AX,YTiles
- NOT AX
- OR AX,DX
- CWD
- NOT DX
- AND SI,DX
- @m0go11:
- {PROCEDURE DrawLeftTile with WriteMode0: }
- { in: ES:DI = ^destination address}
- { SI = tile index }
- { StartLesePlane = first bitplane to read from }
- { LINESIZE_sub_BytesPerPlane, BytesPerPlane = correction factors}
- { leftcut, leftcutDIV4, Win*, SCROLLADR,...}
- {out: ES:DI = ^destination address of the next tile below}
- {rem: WriteMode0 has been set already and remains set }
- MOV AL,[OFFSET BackTile +SI]
- XOR AH,AH {compute offset address of tile: }
- MOV CL,6 {each tile is 64 bytes in size, thus}
- SHL AX,CL {AX := tile * 64 = tile SHL 6 }
- MOV SI,AX
-
- PUSH BP
- ADD SI,leftcutDIV4
- MOV DX,3C4h
- MOV AX,0102h
- OUT DX,AX
- MOV DX,3CEh
- MOV AX,StartLesePlane
- OUT DX,AX
- MOV BX,AX
-
- MOV AX,16+3
- SUB AX,leftcut
- PUSH AX
- SHR AX,1
- SHR AX,1
- MOV BP,AX
- MOV AX,LINESIZE
- SUB AX,BP
- MOV DX,4
- SUB DX,BP
-
- MOV DS,SCROLLADR
-
- PUSH SI
- PUSH DI
- MOV CX,BP {1.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX {ES:DI = ^next tile }
-
- MOV CX,BP {2.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {3.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {4.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {5.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {6.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {7.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {8.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {9.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {10.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {11.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {12.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {13.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {14.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {15.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {16.row }
- REP MOVSB
-
- POP DI
- POP SI
-
- POP BP
- INC BH
- AND BH,3
- JNE @nowrap11a
- INC SI
- @nowrap11a:
- MOV AX,BX
- MOV DX,3CEh
- OUT DX,AX
- MOV DX,3C4h
- MOV AX,0202h
- OUT DX,AX
-
- DEC BP
- PUSH BP
- SHR BP,1
- SHR BP,1
- MOV AX,LINESIZE
- SUB AX,BP
- MOV DX,4
- SUB DX,BP
-
- PUSH SI
- PUSH DI
- MOV CX,BP {1.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX {ES:DI = ^next tile }
-
- MOV CX,BP {2.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {3.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {4.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {5.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {6.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {7.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {8.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {9.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {10.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {11.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {12.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {13.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {14.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {15.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {16.row }
- REP MOVSB
-
- POP DI
- POP SI
-
- POP BP
- INC BH
- AND BH,3
- JNE @nowrap11b
- INC SI
- @nowrap11b:
- MOV AX,BX
- MOV DX,3CEh
- OUT DX,AX
- MOV DX,3C4h
- MOV AX,0402h
- OUT DX,AX
-
- DEC BP
- PUSH BP
- SHR BP,1
- SHR BP,1
- MOV AX,LINESIZE
- SUB AX,BP
- MOV DX,4
- SUB DX,BP
-
- PUSH SI
- PUSH DI
- MOV CX,BP {1.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX {ES:DI = ^next tile }
-
- MOV CX,BP {2.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {3.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {4.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {5.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {6.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {7.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {8.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {9.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {10.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {11.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {12.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {13.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {14.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {15.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {16.row }
- REP MOVSB
-
- POP DI
- POP SI
-
- POP BP
- INC BH
- AND BH,3
- JNE @nowrap11c
- INC SI
- @nowrap11c:
- MOV AX,BX
- MOV DX,3CEh
- OUT DX,AX
- MOV DX,3C4h
- MOV AX,0802h
- OUT DX,AX
-
- DEC BP
-
- SHR BP,1
- SHR BP,1
- MOV AX,LINESIZE
- SUB AX,BP
- MOV DX,4
- SUB DX,BP
-
-
-
- MOV CX,BP {1.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX {ES:DI = ^next tile }
-
- MOV CX,BP {2.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {3.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {4.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {5.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {6.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {7.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {8.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {9.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {10.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {11.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {12.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {13.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {14.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {15.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {16.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- POP BP
- MOV AX,SEG @DATA
- MOV DS,AX
-
- {next tile; DI already has the right value}
- MOV AX,XTiles
- ADD actIndex,AX
- { MOV AX,16 }
- { ADD y,AX }
- INC ytil
-
- DEC counter
- JNZ @m0repeat5
-
- POP DI
- POP ytil
- { POP y }
- POP actIndex
-
- @m0LeftLoopDone:
- INC actIndex
- ADD DI,BytesPerPlane
-
- {-1, because "inc di" has been executed exactly 1x}
- DEC DI
-
- INC xtil
- { MOV AX,16 }
- { SUB AX,leftcut }
- { ADD x,AX }
-
- @m0SkipLeftColumn:
- {ES:DI = ^destination address of the first inner tile (still)}
-
- MOV AX,innerTilesY {are there any inner tiles at all?}
- OR AX,AX
- JBE @m0SkipInnerTiles {no }
- CMP innerTilesX,0
- JB @m0SkipInnerTiles
-
- MOV counter,AX
- MOV AX,actIndex {make copies of the actual values }
- MOV tempActIndex,AX
- { MOV AX,x }
- { MOV tempX,AX }
- MOV AX,xtil
- MOV tempXtil,AX
- { MOV AX,y }
- { MOV tempY,AX }
- MOV AX,ytil
- MOV tempYtil,AX
- MOV tempDI,DI
-
- CMP rightcut,0
- JE @m0SkipRightColumn
-
- MOV DX,16
- SUB DX,rightcut
- SHR DX,1
- SHR DX,1
- MOV BytesPerPlane,DX
- MOV AX,LINESIZE
- SUB AX,DX
- MOV LINESIZE_sub_BytesPerPlane,AX
-
- MOV AX,innerTilesX
- ADD xtil,AX
- ADD actIndex,AX
- MOV CL,2
- SHL AX,CL
- ADD DI,AX {ES:DI = ^first right corner tile being not cut at its top }
- { SHL AX,CL }
- { ADD x,AX }
-
- MOV AX,xtil
- CWD
- SUB AX,XTiles
- NOT AX
- OR AX,DX
- CWD
- NOT DX
- MOV Xoffscreen,DX
-
- @m0repeat6:
- MOV SI,actIndex
- AND SI,Xoffscreen
- JZ @m0go12
- MOV AX,ytil
- CWD
- SUB AX,YTiles
- NOT AX
- OR AX,DX
- CWD
- NOT DX
- AND SI,DX
- @m0go12:
- {PROCEDURE DrawRightTile with WriteMode0: }
- { in: ES:DI = ^destination address}
- { SI = tile index }
- { StartWritePlane = first bitplane to write to }
- { innerTilesY >= 1 }
- { rightcut, Win*, SCROLLADR,...}
- {out: ES:DI = ^destination address of the next tile below}
- {rem: WriteMode0 has been set already and remains set }
- MOV AL,[OFFSET BackTile +SI]
- XOR AH,AH {compute offset address of tile: }
- MOV CL,6 {each tile is 64 bytes in size, thus}
- SHL AX,CL {AX := tile * 64 = tile SHL 6 }
- MOV SI,AX
-
- PUSH BP
- MOV DX,3C4h
- MOV AX,StartWritePlane
- OUT DX,AX
- MOV BX,AX
- MOV DX,3CEh
- MOV AX,0004h
- OUT DX,AX
-
- MOV AX,16+3
- SUB AX,rightcut
- PUSH AX
- SHR AX,1
- SHR AX,1
- MOV BP,AX
- MOV AX,LINESIZE
- SUB AX,BP
- MOV DX,4
- SUB DX,BP
-
- MOV DS,SCROLLADR
-
- PUSH SI
- PUSH DI
- MOV CX,BP {1.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX {ES:DI = ^next tile }
-
- MOV CX,BP {2.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {3.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {4.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {5.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {6.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {7.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {8.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {9.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {10.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {11.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {12.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {13.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {14.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {15.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {16.row }
- REP MOVSB
-
- POP DI
- POP SI
-
- POP BP
- SHL BH,1
- CMP BH,16
- JNE @nowrap12a
- MOV BH,1
- INC DI
- @nowrap12a:
- MOV AX,BX
- MOV DX,3C4h
- OUT DX,AX
- MOV DX,3CEh
- MOV AX,0104h
- OUT DX,AX
-
- DEC BP
- PUSH BP
- SHR BP,1
- SHR BP,1
- MOV AX,LINESIZE
- SUB AX,BP
- MOV DX,4
- SUB DX,BP
-
- PUSH SI
- PUSH DI
- MOV CX,BP {1.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX {ES:DI = ^next tile }
-
- MOV CX,BP {2.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {3.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {4.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {5.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {6.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {7.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {8.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {9.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {10.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {11.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {12.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {13.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {14.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {15.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {16.row }
- REP MOVSB
-
- POP DI
- POP SI
-
- POP BP
- SHL BH,1
- CMP BH,16
- JNE @nowrap12b
- MOV BH,1
- INC DI
- @nowrap12b:
- MOV AX,BX
- MOV DX,3C4h
- OUT DX,AX
- MOV DX,3CEh
- MOV AX,0204h
- OUT DX,AX
-
- DEC BP
- PUSH BP
- SHR BP,1
- SHR BP,1
- MOV AX,LINESIZE
- SUB AX,BP
- MOV DX,4
- SUB DX,BP
-
- PUSH SI
- PUSH DI
- MOV CX,BP {1.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX {ES:DI = ^next tile }
-
- MOV CX,BP {2.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {3.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {4.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {5.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {6.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {7.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {8.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {9.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {10.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {11.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {12.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {13.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {14.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {15.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {16.row }
- REP MOVSB
-
- POP DI
- POP SI
-
- POP BP
- SHL BH,1
- CMP BH,16
- JNE @nowrap12c
- MOV BH,1
- INC DI
- @nowrap12c:
- MOV AX,BX
- MOV DX,3C4h
- OUT DX,AX
- MOV DX,3CEh
- MOV AX,0304h
- OUT DX,AX
-
- DEC BP
-
- SHR BP,1
- SHR BP,1
- MOV AX,LINESIZE
- SUB AX,BP
- MOV DX,4
- SUB DX,BP
-
-
-
- MOV CX,BP {1.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX {ES:DI = ^next tile }
-
- MOV CX,BP {2.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {3.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {4.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {5.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {6.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {7.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {8.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {9.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {10.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {11.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {12.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {13.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {14.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {15.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- MOV CX,BP {16.row }
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
-
- DEC DI
-
-
- POP BP
- MOV AX,SEG @DATA
- MOV DS,AX
-
- {next tile; DI already has the right value}
- MOV AX,XTiles
- ADD actIndex,AX
- { MOV AX,16 }
- { ADD y,AX }
- INC ytil
-
- DEC counter
- JNZ @m0repeat6
-
- MOV DI,tempDI
- MOV AX,tempActIndex
- MOV actIndex,AX
- { MOV AX,tempX }
- { MOV x,tempX }
- MOV AX,tempXtil
- MOV xtil,AX
- { MOV AX,tempY }
- { MOV y,AX }
- MOV AX,tempYtil
- MOV ytil,AX
-
- @m0RightLoopDone:
- @m0SkipRightColumn:
- {ES:DI = ^destination address of the first inner tile (still)}
- {innerTilesX >= 0, innerTilesX >= 1 -> it would suffice to check innerTilesX=0:}
-
- CMP innerTilesX,0 {IF (innerTilesX <= 0) OR (innerTilesY <= 0) THEN skip}
- JBE @m0SkipInnerTiles {If there are no inner tiles, then the }
- {actual position is located at the 1st tile which }
- {is not cut at its left and is in the lowest tile row }
-
-
- {now "FOR x:=1 TO innerTilesX DO FOR y:=1 TO innerTilesY DO .." }
- MOV oldDI,DI {make temporary copies of DI and actIndex }
- MOV AX,actIndex
- MOV oldActIndex,AX
-
- MOV AX,innerTilesX
- MOV counter,AX {counter for X-direction}
- MOV CL,6
-
- @m0xloop:
- MOV AX,xtil
- CWD
- SUB AX,XTiles
- NOT AX
- OR AX,DX
- CWD
- NOT DX
- MOV Xoffscreen,DX {is a constant for the tile column}
-
- MOV AX,innerTilesY
- MOV CH,AL {CH is used as a counter for the Y-direction}
-
-
- @m0yloop:
- MOV SI,oldActIndex {SI = temp. actIndex}
- AND SI,Xoffscreen
- JZ @m0go5
- MOV AX,ytil
- CWD
- SUB AX,YTiles
- NOT AX
- OR AX,DX
- CWD
- NOT DX
- AND SI,DX
- @m0go5:
- {PROCEDURE DrawInnerTile with WriteMode0: }
- { in: ES:DI = ^destination address}
- { SI = tile index }
- { CL = 6 }
- { SCROLLADR}
- {out: ES:DI = ^destination address of the next tile below}
- { CL = 6}
- {rem: WriteMode0 has been set already and remains set }
- { CH will not be changed! }
- MOV AL,[OFFSET BackTile +SI]
- XOR AH,AH {compute offset address of tile: }
- {each tile is 64 bytes in size, thus}
- SHL AX,CL {AX := tile * 64 = tile SHL 6 }
- MOV SI,AX
-
- MOV DS,SCROLLADR
-
- MOV DX,3C4h
- MOV AX,StartWritePlane
- MOV BX,AX
- OUT DX,AX
- MOV DX,3CEh
- MOV AX,0004h
- OUT DX,AX
-
- MOVSW {1.row }
- MOVSW
- ADD DI,LINESIZE-4 {ES:DI = ^next tile }
-
- MOVSW {2.row }
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {3.row }
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {4.row }
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {5.row }
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {6.row }
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {7.row }
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {8.row }
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {9.row }
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {10.row }
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {11.row }
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {12.row }
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {13.row }
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {14.row }
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {15.row }
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {16.row }
- MOVSW
-
- SUB SI,16*4
- SUB DI,15*LINESIZE +4
-
- MOV AX,0104h
- OUT DX,AX {DX = 3CEh}
- SHL BH,1
- CMP BH,16
- JNE @nowrap5a
- MOV BH,1
- INC DI
- @nowrap5a:
- MOV AX,BX
- MOV DX,3C4h
- OUT DX,AX
-
- MOVSW {1.row }
- MOVSW
- ADD DI,LINESIZE-4 {ES:DI = ^next tile }
-
- MOVSW {2.row }
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {3.row }
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {4.row }
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {5.row }
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {6.row }
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {7.row }
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {8.row }
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {9.row }
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {10.row }
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {11.row }
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {12.row }
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {13.row }
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {14.row }
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {15.row }
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {16.row }
- MOVSW
-
- SUB SI,16*4
- SUB DI,15*LINESIZE +4
-
- SHL BH,1
- CMP BH,16
- JNE @nowrap5b
- MOV BH,1
- INC DI
- @nowrap5b:
- MOV AX,BX
- OUT DX,AX {DX = 3C4h}
- MOV DX,3CEh
- MOV AX,0204h
- OUT DX,AX
-
- MOVSW {1.row }
- MOVSW
- ADD DI,LINESIZE-4 {ES:DI = ^next tile }
-
- MOVSW {2.row }
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {3.row }
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {4.row }
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {5.row }
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {6.row }
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {7.row }
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {8.row }
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {9.row }
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {10.row }
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {11.row }
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {12.row }
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {13.row }
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {14.row }
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {15.row }
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {16.row }
- MOVSW
-
- SUB SI,16*4
- SUB DI,15*LINESIZE +4
-
- MOV AX,0304h
- OUT DX,AX {DX = 3CEh}
- SHL BH,1
- CMP BH,16
- JNE @nowrap5c
- MOV BH,1
- INC DI
- @nowrap5c:
- MOV AX,BX
- MOV DX,3C4h
- OUT DX,AX
-
- MOVSW {1.row }
- MOVSW
- ADD DI,LINESIZE-4 {ES:DI = ^next tile }
-
- MOVSW {2.row }
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {3.row }
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {4.row }
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {5.row }
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {6.row }
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {7.row }
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {8.row }
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {9.row }
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {10.row }
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {11.row }
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {12.row }
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {13.row }
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {14.row }
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {15.row }
- MOVSW
- ADD DI,LINESIZE-4
-
- MOVSW {16.row }
- MOVSW
-
-
- MOV AX,SEG @Data
- MOV DS,AX
-
- ADD DI,LINESIZE-4-1
-
- {next tile; DI already has the right value}
- MOV AX,XTiles {set temp. actIndex to next row }
- ADD oldActIndex,AX
- INC ytil
- { MOV AX,16 }
- { ADD y,AX }
-
- DEC CH
- JNZ @m0yloop
-
- {actIndex still has its old value, as only oldActIndex has been changed. }
- INC actIndex {actIndex = next inner tile in uppermost tile row }
- MOV AX,actIndex {and use it as starting value for next column }
- MOV oldActIndex,AX
-
- MOV DI,oldDI {ES:DI = ^inner tile in uppermost tile row }
- ADD DI,4 {increment by one tile }
- MOV oldDI,DI {and use it as starting value for next column }
-
- MOV AX,tempYtil
- MOV ytil,AX {set Y-coordinate back to the uppermost inner tile row }
- { MOV AX,oldY }
- { MOV y,AX }
-
- INC xtil {increment X-coordinate by one tile column }
- { MOV AX,16 }
- { ADD x,AX }
-
- DEC counter
- JNZ @m0xloop
-
- MOV DI,tempDI {Thus: ES:DI, actIndex, xtil, ytil, x, y point to }
- MOV AX,tempActIndex {the first inner tile again (N.B.: y, ytil have }
- MOV actIndex,AX {restored some lines above, already! }
- MOV AX,tempXtil
- MOV xtil,AX
- { MOV AX,tempX }
- { MOV x,AX }
-
- MOV AX,innerTilesY
- MOV DX,AX {hold a copy in DX }
- ADD ytil,AX {ytil points to the bottommost tile row }
-
- MOV CL,5
- SHL AX,CL {dto. for DI: inc(DI,16 * innerTilesY * LINESIZE) }
- MOV BX,AX
- ADD DI,CS:[OFFSET GADR +BX]
- { SHR AX,1 }
- { ADD y,AX } {dto. for y: inc(y,16 * innerTilesY) }
-
- MOV AX,XTiles
- MUL DX {AX := XTiles * innerTilesY}
- ADD actIndex,AX {dto. for actIndex: inc(actIndex,XTiles * innerTilesY) }
-
- @m0SkipInnerTiles:
- {ES:DI, actIndex, xtil, ytil, x, y point to the first inner tile of the}
- {bottommost tile row }
- CMP bottomcut,0
- JE @m0fertig
-
- MOV AX,ytil
- CWD
- SUB AX,YTiles
- NOT AX
- OR AX,DX
- CWD
- NOT DX
- MOV Yoffscreen,DX
-
- MOV AX,innerTilesX
- OR AX,AX
- JBE @m0LowerInnerTilesDone {are we standing at the right bottom corner tile? }
- MOV counter,AX
-
- {compute addition factor needed to position from bottom to top:}
- {┌─┬─┬─┬─┐ ┌─┬─┬─┬─┐▄ }
- {├─┼─┼─┼─┤ ─> ├─┼─┼─┼─┤ }
- {└─┴─┴─┴─┘ └─┴─┴─┴─┘ }
- { ▀ }
- {Korrektur:=-(16 - bottomcut) * LINESIZE + 4}
- MOV BX,16
- SUB BX,bottomcut
- SHL BX,1
- MOV AX,CS:[OFFSET GADR +BX]
- NEG AX
- ADD AX,4-1 {-1, because DI has been inremented 1x (due to planing)}
- MOV Korrektur,AX
-
- @m0repeat4:
- MOV SI,actIndex
- AND SI,Yoffscreen
- JZ @m0go8
-
- MOV AX,xtil
- CWD
- SUB AX,XTiles
- NOT AX
- OR AX,DX
- CWD
- NOT DX
- AND SI,DX
- @m0go8:
- {PROCEDURE DrawLowerInnerTile with WriteMode0: }
- { in: ES:DI = ^destination address}
- { SI = tile index }
- { bottomcut, Win*, SCROLLADR,...}
- {out: ES:DI = ^destination address of the next tile to the right of it}
- {rem: WriteMode0 has been set already and remains set }
- MOV AL,[OFFSET BackTile +SI]
- XOR AH,AH {compute offset address of tile: }
- MOV CL,6 {each tile is 64 bytes in size, thus}
- SHL AX,CL {AX := tile * 64 = tile SHL 6 }
- MOV SI,AX
-
- MOV CX,16
- SUB CX,bottomcut
-
- MOV DX,3CEh
- MOV AX,0004h
- OUT DX,AX
- MOV DX,3C4h
- MOV AX,StartWritePlane
- OUT DX,AX
-
- MOV DS,SCROLLADR
-
- MOV BX,CX
- PUSH SI
- PUSH DI
- @m0eineZeile4e1:
- MOVSW
- MOVSW
- ADD DI,LINESIZE-4
- LOOP @m0eineZeile4e1
- POP DI
- POP SI
- MOV CX,BX
-
- SHL AH,1
- CMP AH,16
- JNE @nowrap8a
- MOV AH,1
- INC DI
- @nowrap8a:
- MOV DX,3C4h
- OUT DX,AX
- MOV BX,AX
- MOV DX,3CEh
- MOV AX,0104h
- OUT DX,AX
-
- MOV AX,CX
- PUSH SI
- PUSH DI
- @m0eineZeile4e2:
- MOVSW
- MOVSW
- ADD DI,LINESIZE-4
- LOOP @m0eineZeile4e2
- POP DI
- POP SI
- MOV CX,AX
-
- MOV DX,3CEh
- MOV AX,0204h
- OUT DX,AX
- SHL BH,1
- CMP BH,16
- JNE @nowrap8b
- MOV BH,1
- INC DI
- @nowrap8b:
- MOV AX,BX
- MOV DX,3C4h
- OUT DX,AX
-
- MOV BX,CX
- PUSH SI
- PUSH DI
- @m0eineZeile4e3:
- MOVSW
- MOVSW
- ADD DI,LINESIZE-4
- LOOP @m0eineZeile4e3
- POP DI
- POP SI
- MOV CX,BX
-
- SHL AH,1
- CMP AH,16
- JNE @nowrap8c
- MOV AH,1
- INC DI
- @nowrap8c:
- MOV DX,3C4h
- OUT DX,AX
- MOV BX,AX
- MOV DX,3CEh
- MOV AX,0304h
- OUT DX,AX
-
- @m0eineZeile4e4:
- MOVSW
- MOVSW
- ADD DI,LINESIZE-4
- LOOP @m0eineZeile4e4
-
-
- MOV AX,SEG @Data
- MOV DS,AX
-
- {DI = ^start of the next row below the tile, now position to the next }
- {tile: }
- {┌─┬─┬─┬─┐ ┌─┬─┬─┬─┐▄ }
- {├─┼─┼─┼─┤ ─> ├─┼─┼─┼─┤ }
- {└─┴─┴─┴─┘ └─┴─┴─┴─┘ }
- { ▀ }
- ADD DI,Korrektur
-
- {position to next tile to the right of it: }
- INC actIndex
- INC xtil
- { MOV AX,16 }
- { ADD x,AX }
-
- DEC counter
- JNZ @m0repeat4
-
- @m0LowerInnerTilesDone:
- {ES:DI, actIndex, xtil, ytil, x, y point to the lower right corner tile}
- CMP rightcut,0
- JE @m0SkipLowerRightCorner
-
- PUSH DI
- MOV SI,actIndex
- AND SI,Yoffscreen
- JZ @m0go9
- MOV AX,xtil
- CWD
- SUB AX,XTiles
- NOT AX
- OR AX,DX
- CWD
- NOT DX
- AND SI,DX
- @m0go9:
- {PROCEDURE DrawLowerRightTile with WriteMode0: }
- { in: ES:DI = ^destination address}
- { SI = tile index }
- { StartWritePlane = first bitplane to write to }
- { rightcut MOD 4 = 0 }
- { rightcut, bottomcut, Win*, SCROLLADR,...}
- {out: ES = ^graphic segment }
- {rem: WriteMode0 has been set already and remains set }
- PUSH BP
- MOV AL,[OFFSET BackTile +SI]
- XOR AH,AH {compute offset address of tile: }
- MOV CL,6 {each tile is 64 bytes in size, thus}
- SHL AX,CL {AX := tile * 64 = tile SHL 6 }
- MOV SI,AX
-
- MOV CX,16
- SUB CX,bottomcut
- MOV BX,16+3
- SUB BX,rightcut
- PUSH BX
- SHR BX,1
- SHR BX,1 {BX = BytesPerPlane = (16 + 3 - rightcut) DIV 4}
-
- MOV DS,SCROLLADR
-
- MOV DX,3C4h
- MOV AX,StartWritePlane
- OUT DX,AX
- PUSH AX
- MOV DX,3CEh
- MOV AX,0004h
- OUT DX,AX
-
- MOV AX,LINESIZE
- SUB AX,BX
- MOV DX,4
- SUB DX,BX
- MOV BP,BX {BP = bytes per row }
- MOV BL,CL {BL = row counter }
- MOV BH,CL {copy to BH }
-
- PUSH SI
- PUSH DI
- @m0eineZeile4g1:
- MOV CX,BP
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
- DEC BL
- JNZ @m0eineZeile4g1
- POP DI
- POP SI
- MOV BL,BH
-
- POP AX
- SHL AH,1
- CMP AH,16
- JNE @nowrap9a
- MOV AH,1
- INC DI
- @nowrap9a:
- MOV DX,3C4h
- OUT DX,AX
- POP BP
- DEC BP
- PUSH BP
- PUSH AX
- MOV DX,3CEh
- MOV AX,0104h
- OUT DX,AX
- SHR BP,1
- SHR BP,1
-
- MOV AX,LINESIZE
- SUB AX,BP
- MOV DX,4
- SUB DX,BP
-
- PUSH SI
- PUSH DI
- @m0eineZeile4g2:
- MOV CX,BP
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
- DEC BL
- JNZ @m0eineZeile4g2
- POP DI
- POP SI
- MOV BL,BH
-
- POP AX
- SHL AH,1
- CMP AH,16
- JNE @nowrap9b
- MOV AH,1
- INC DI
- @nowrap9b:
- MOV DX,3C4h
- OUT DX,AX
- POP BP
- DEC BP
- PUSH BP
- PUSH AX
- MOV DX,3CEh
- MOV AX,0204h
- OUT DX,AX
- SHR BP,1
- SHR BP,1
-
- MOV AX,LINESIZE
- SUB AX,BP
- MOV DX,4
- SUB DX,BP
-
- PUSH SI
- PUSH DI
- @m0eineZeile4g3:
- MOV CX,BP
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
- DEC BL
- JNZ @m0eineZeile4g3
- POP DI
- POP SI
- MOV BL,BH
-
- POP AX
- SHL AH,1
- CMP AH,16
- JNE @nowrap9c
- MOV AH,1
- INC DI
- @nowrap9c:
- MOV DX,3C4h
- OUT DX,AX
- POP BP
- DEC BP
- MOV DX,3CEh
- MOV AX,0304h
- OUT DX,AX
- SHR BP,1
- SHR BP,1
-
- MOV AX,LINESIZE
- SUB AX,BP
- MOV DX,4
- SUB DX,BP
-
- @m0eineZeile4g4:
- MOV CX,BP
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
- DEC BL
- JNZ @m0eineZeile4g4
-
-
- POP BP
- MOV AX,SEG @DATA
- MOV DS,AX
-
- POP DI {ES:DI etc. point to lower right corner tile }
-
- @m0SkipLowerRightCorner:
- CMP leftcut,0
- JE @m0fertig
-
- {now position on lower left corner tile: }
- MOV AX,innerTilesX
- INC AX
- SUB actIndex,AX {dec(actIndex,innerTilesX + 1) }
- SUB xtil,AX {dec(xtil,innerTilesX + 1) }
- MOV CL,2
- SHL AX,CL
- SUB DI,AX {dec(DI,4 * (innerTilesX + 1) }
- ADD DI,leftcutDIV4 {don't forget: corner tile may be cut at its left side}
- INC DI
- { MOV AX,WinXMIN }
- { MOV x,AX }
-
- MOV SI,actIndex
- AND SI,Yoffscreen
- JZ @m0go7
- MOV AX,xtil
- CWD
- SUB AX,XTiles
- NOT AX
- OR AX,DX
- CWD
- NOT DX
- AND SI,DX
- @m0go7:
- {PROCEDURE DrawLowerLeftTile with WriteMode0: }
- { in: ES:DI = ^destination address}
- { SI = tile index }
- { StartLesePlane = first bitplane to read from }
- { rightcut MOD 4 = 0 }
- { leftcut, bottomcut, Win*, SCROLLADR,...}
- {out: (ES = ^graphic segment) }
- {rem: WriteMode0 has been set (and remains set) }
- PUSH BP
- MOV AL,[OFFSET BackTile +SI]
- XOR AH,AH {compute offset address of tile: }
- MOV CL,6 {each tile is 64 bytes in size, thus}
- SHL AX,CL {AX := tile * 64 = tile SHL 6 }
- MOV SI,AX
-
- MOV AX,leftcut
- MOV BX,AX
- MOV CL,2
- SHR AX,CL
- ADD SI,AX
-
- MOV CX,16
- SUB CX,bottomcut
-
- MOV DS,SCROLLADR
-
- MOV DX,3C4h
- MOV AX,0102h
- OUT DX,AX
- MOV DX,3CEh
- MOV AX,StartLesePlane
- OUT DX,AX
-
- MOV BP,16+3
- SUB BP,BX
- PUSH BP
- PUSH AX
- SHR BP,1
- SHR BP,1 {BP := (16 + 3 - leftcut) DIV 4}
-
- MOV AX,LINESIZE
- SUB AX,BP
- MOV DX,4
- SUB DX,BP
-
- MOV BL,CL {BL=row counter }
- MOV BH,CL {copy of it }
-
- PUSH SI
- PUSH DI
- @m0eineZeile4d1:
- MOV CX,BP
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
- DEC BL
- JNZ @m0eineZeile4d1
- POP DI
- POP SI
-
- POP AX
- INC AH
- AND AH,3
- JNE @nowrap7a
- INC SI
- @nowrap7a:
- MOV DX,3CEh
- OUT DX,AX
- POP BP
- DEC BP
- PUSH BP
- PUSH AX
- MOV DX,3C4h
- MOV AX,0202h
- OUT DX,AX
- SHR BP,1
- SHR BP,1
- MOV AX,LINESIZE
- SUB AX,BP
- MOV DX,4
- SUB DX,BP
- MOV BL,BH
-
- PUSH SI
- PUSH DI
- @m0eineZeile4d2:
- MOV CX,BP
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
- DEC BL
- JNZ @m0eineZeile4d2
- POP DI
- POP SI
-
- POP AX
- INC AH
- AND AH,3
- JNE @nowrap7b
- INC SI
- @nowrap7b:
- MOV DX,3CEh
- OUT DX,AX
- POP BP
- DEC BP
- PUSH BP
- PUSH AX
- MOV DX,3C4h
- MOV AX,0402h
- OUT DX,AX
- SHR BP,1
- SHR BP,1
- MOV AX,LINESIZE
- SUB AX,BP
- MOV DX,4
- SUB DX,BP
- MOV BL,BH
-
- PUSH SI
- PUSH DI
- @m0eineZeile4d3:
- MOV CX,BP
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
- DEC BL
- JNZ @m0eineZeile4d3
- POP DI
- POP SI
-
- POP AX
- INC AH
- AND AH,3
- JNE @nowrap7c
- INC SI
- @nowrap7c:
- MOV DX,3CEh
- OUT DX,AX
- POP BP
- DEC BP
- MOV DX,3C4h
- MOV AX,0802h
- OUT DX,AX
- SHR BP,1
- SHR BP,1
- MOV AX,LINESIZE
- SUB AX,BP
- MOV DX,4
- SUB DX,BP
- MOV BL,BH
-
- @m0eineZeile4d4:
- MOV CX,BP
- REP MOVSB
- ADD SI,DX
- ADD DI,AX
- DEC BL
- JNZ @m0eineZeile4d4
-
-
- POP BP
- MOV AX,SEG @DATA
- MOV DS,AX
-
- @m0fertig:
-
-
- {------- starting here: put sprites on actual graphic page}
-
- @Sprites_zeichnen:
- MOV SI,NMAX*2
- PUSH BP {pop BP in the end! }
-
-
- @zeichne:
- CMP SI,SplitIndex_mal2 {split index?}
- JNE @SZeich
-
- MOV AX,WinXMIN
- {yes: set Win* variables to the whole area (0,0)..(XMAX,YMAX):}
- OR AX,WinYMIN
- JNZ @replace1
- CMP WinXMAX,XMAX
- JNE @replace2
- CMP WinYMAX,YMAX
- JE @replacedone
- JMP @replace3 {short}
-
- @replace1:
- MOV WinXMIN,0
- MOV WinYMIN,0
- MOV WinXMINdiv4,0
- MOV WinYMIN_mul_LINESIZE,0
- MOV WinYMINmLINESIZEaWinXMINdiv4,0
- @replace2:
- MOV WinXMAX,XMAX
- MOV WinWidth,XMAX+1
- MOV WinWidthDiv4,(XMAX+1)/4
- @replace3:
- MOV WinYMAX,YMAX
- MOV WinHeight,YMAX+1
- MOV WinLowerRight,0
- @replacedone:
-
- {DS = normal data segment, ES = graphic page segment, }
- {SI = sprite position number * 2 }
- @SZeich:
- MOV BX,[SI + OFFSET SpriteN] {BX = SpriteN[?] = sprite load number}
- SHL BX,1 {BX = sprite load number * 2}
-
- {now: compute "SpriteN[?] := SpriteN[NextSprite[?]]" }
- MOV BX,[BX + OFFSET NextSprite] {AX = NextSprite[SpriteN[?]]}
- MOV [SI + OFFSET SpriteN],BX {use it as new SpriteN[?] value}
- SHL BX,1
-
-
- JNZ @aktiv
- JMP @noSprite
-
-
- @aktiv:
- PUSH SI {save sprite position number * 2 }
-
- MOV DX,[SI + OFFSET SpriteX] {if SpriteX > xmax then skip_sprite}
- SUB DX,StartVirtualX {virtual -> absolute coordinates }
- MOV AX,WinXMAX
- CMP DX,AX
- JLE @L0
- @ToSprite_fertig: {jump-rail to @Sprite_fertig }
- JMP @Sprite_fertig
- @L0:
- MOV CS:WORD PTR @akt_SpriteX+1,DX
- MOV DI,[SI + OFFSET SpriteY] {DI = SpriteY_virtual }
- SUB DI,StartVirtualY {DI = SpriteY (absolute!)}
-
- PUSH AX {WinXMAX}
- MOV AX,WinYMIN
- MOV SI,WinXMIN
- MOV CX,WinYMAX {save old Win* values... }
-
- MOV DS,[BX + OFFSET SPRITEAD] {!!!DS = ^sprite data !!!}
-
- MOV [WinYMIN_],AX {...and store them in new DS segment}
- MOV [WinXMIN_],SI
- POP AX
- MOV [WinXMAX_],AX {hold WinYMAX in CX }
-
- MOV AX,[Breite] {AX = width in groups of 4 }
- MOV CS:WORD PTR @max_Breite+1,AX
- MOV SI,AX {SI = dto.}
- SHL AX,1
- SHL AX,1 {AX = max_width_in_points }
- ADD AX,DX {AX = max_width_in_points+SpriteX }
- CMP AX,[WinXMIN_] {is the right end to the left of the window area?}
- JL @ToSprite_fertig
- MOV BX,DI {if SpriteY - WinYMIN >= 0 }
- SUB DI,[WinYMIN_] { then starty := 0}
- NEG DI { else starty := -(SpriteY - WinYMIN)}
- MOV BP,DI
- JG @Top_cut
- XOR DI,DI
- @Top_cut: {DI = starty, BP = -(SpriteY - WinYMIN)}
- MOV AX,[Hoehe] {AX = height (in rows) }
- CMP DI,AX {if starty >= height then skip_sprite}
- JGE @ToSprite_fertig
- ADD BP,CX {BP = -(SpriteY - WinYMIN) + WinYMAX}
- SUB BP,[WinYMIN_]
- JL @ToSprite_fertig {(a bit lax:) }
- CMP AX,BP {if height + SpriteY > WinYMAX }
- JG @To_then { then [ endy := WinYMAX - SpriteY }
- DEC AX { if endy < 0 then skip_sprite ] }
- MOV BP,AX { else endy := height - 1 }
-
- {BP = endy, SI=[@max_Breite+1] = max_width_in_groups of 4, }
- {DI = starty, BX = SpriteY, DX=[@akt_SpriteX+1] = SpriteX, }
- {DS = ^sprite data, ES = ^graphic page}
- @To_then:
- MOV AX,BP
- SUB BP,DI
-
- SHL BP,1
- MOV [End_min_Start],BP {= (endy - starty) * 2 =Yactual * 2 }
- ADD BX,AX
- SHL BX,1
- MOV BX,CS:[OFFSET gadr + BX] {BX =zeilenadr :=(endy + SpriteY) * LINESIZE}
- MOV [zeilenadr],BX {store it in [zeilenadr], too }
- MOV BP,DX
- MUL SI {AX = endy * max_width_in_groups_of_4 = yoffset}
- MOV [yoffset_],AX {store it in [yoffset_], too}
- SHL DI,1 {DI = starty * 2}
- MOV CS:WORD PTR @Starty_2+1,DI {store in [@Starty_2 + 1], too }
-
- {Now: look at sprite's mode byte and determine if an other than the }
- {momentary active sprite display method is needed; if so, then copy }
- {in the right one! }
- {used registers: AX and SI }
- MOV AL,[Modus] {get mode byte of the sprite}
- XOR AH,AH
- SHL AX,1
- MOV SI,AX
- MOV SI,CS:[OFFSET Adressen +SI] {get pointer to according routine }
- MOV AX,CS:[SI]
- CMP AX,CS:[WORD PTR @Patch1] {is this routine already active? }
- JE @no_newcode {yes, nothing to do}
- PUSH DS {no, copy routine to all places }
- PUSH CS {where it will be needed}
- POP DS
- MOV [WORD PTR @Patch1],AX
- MOV [WORD PTR @Patch2],AX
- MOV [WORD PTR @Patch3],AX
- MOV [WORD PTR @Patch4],AX
- INC SI
- INC SI
- LODSW
- MOV [WORD PTR @Patch1+2],AX
- MOV [WORD PTR @Patch2+2],AX
- MOV [WORD PTR @Patch3+2],AX
- MOV [WORD PTR @Patch4+2],AX
- LODSW
- MOV [WORD PTR @Patch1+4],AX
- MOV [WORD PTR @Patch2+4],AX
- MOV [WORD PTR @Patch3+4],AX
- MOV [WORD PTR @Patch4+4],AX
- LODSW
- MOV [WORD PTR @Patch1+6],AX
- MOV [WORD PTR @Patch2+6],AX
- MOV [WORD PTR @Patch3+6],AX
- MOV [WORD PTR @Patch4+6],AX
- LODSW
- MOV [WORD PTR @Patch1+8],AX
- MOV [WORD PTR @Patch2+8],AX
- MOV [WORD PTR @Patch3+8],AX
- MOV [WORD PTR @Patch4+8],AX
- LODSW
- MOV [WORD PTR @Patch1+10],AX
- MOV [WORD PTR @Patch2+10],AX
- MOV [WORD PTR @Patch3+10],AX
- MOV [WORD PTR @Patch4+10],AX
- LODSW
- MOV [WORD PTR @Patch1+12],AX
- MOV [WORD PTR @Patch2+12],AX
- MOV [WORD PTR @Patch3+12],AX
- MOV [WORD PTR @Patch4+12],AX
- LODSW
- MOV [WORD PTR @Patch1+14],AX
- MOV [WORD PTR @Patch2+14],AX
- MOV [WORD PTR @Patch3+14],AX
- MOV [WORD PTR @Patch4+14],AX
-
- POP DS {restore DS }
- @no_newcode:
-
-
- {(AX=)[yoffset_] = yoffset }
- { BX = [zeilenadr] = (endy + SpriteY) * LINESIZE}
- { CX = WinYMAX }
- { DI = [@Starty_2 + 1] = starty * 2}
- {(SI = [@max_Breite + 1] = max_width_in_groups_of_4) }
- { BP = [@akt_SpriteX + 1]= SpriteX}
- { DS = ^sprite data}
- { ES = ^graphic page}
- { [end_min_start] = (endy - starty) * 2 = Yactual * 2 }
- { [@max_Breite + 1] = max_width_in_groups_of_4 }
- @eine_Zeile:
- MOV SI,[end_min_start] {SI = Yactual * 2 }
- ADD SI,DI {startx := sprite[WORD PTR sprite[L] + }
- MOV DI,SI { (Yactual + starty) * 2] }
- ADD SI,[Left]
- MOV SI,[SI] {SI = startx, DI = (Yactual + starty) * 2 }
- MOV AX,BP
- MOV DX,AX {AX = DX = SpriteX}
- SUB BP,[WinXMIN_] {BP = SpriteX - WinXMIN}
- ADD AX,SI {AX = ScreenStartX := SpriteX + startx }
- CMP AX,[WinXMAX_] {if ScreenStartX > WinXMAX then skip_zeile }
- JG @ToZeile_fertig
- MOV CX,SI {CX = startx}
- SUB AX,[WinXMIN_] {lecutoff_in_points := startx }
- JGE @L1 {if ScreenStartX < WinXMIN then }
- SUB SI,AX { [dec(startx,ScreenStartX - WinXMIN) }
- XOR AX,AX { ScreenStartX := WinXMIN }
- MOV CX,BP { lecutoff_in_points := -SpriteX] }
- NEG CX
- @L1:
- ADD AX,[WinXMIN_] {CX = [licutoff_] = lecutoff_in_points, }
- MOV [licutoff_],CX {SI = startx, AX = ScreenStartX }
- ADD DI,[Right]
- MOV DI,[DI] {DI = endx := sprite[WORD PTR sprite[R] + }
- { (Yactual + starty) * 2] }
- NEG DX {DX = -SpriteX }
- MOV BP,DI
- SUB BP,SI {BP = endx - startx }
- SUB DX,DI {DX = -(SpriteX + endx) }
- ADD DX,[WinXMAX_] {DX = overhang := WinXMAX - (SpriteX + endx) }
- JNS @kein_Ueberhang_rechts
- ADD BP,DX
- @kein_Ueberhang_rechts: {BP = visible width of this row -1 }
- OR BP,BP
- JNS @L6
- @ToZeile_fertig:
- JMP @Zeile_fertig {if width <= 0 then skip_zeile }
- @L6:
- ADD BP,4
-
- { AX = ScreenStartX }
- { BX = [zeilenadr] = (endy + SpriteY) * LINESIZE }
- { CX = [licutoff_] = lecutoff_in_points }
- {(DX = (negative) overhang (if value < 0) ) }
- {(SI = startx) }
- {(DI = endx) }
- { BP = width of this row in pixels + 3 }
- { DS = ^sprite data}
- { ES = ^graphic page}
- { [@max_Breite + 1] = max_width_in_groups_of_4) }
- { [end_min_start] = (endy - starty) * 2 =Yactual * 2 }
- { [@Starty_2 + 1] = starty * 2}
- { [@max_Breite + 1] = max_width_in_groups_of_4, }
- { [@akt_SpriteX + 1] = SpriteX}
- MOV [bildx],AX {save ScreenStartX }
- MOV DX,CX {DX = lecutoff_in_points }
- MOV CX,BP
- SHR CX,1
- SHR CX,1 {CX = width DIV 4 }
- JCXZ @Plane1
-
- {SI = source pointer := sprite[WORD PTR (lecutoff_in_points + 0 AND 3) * 2}
- { + (lecutoff_in_points + 0) DIV 4 + yoffset }
- MOV SI,DX
- AND SI,3
- SHL SI,1 {SI = ((lecutoff_in_points + 0) AND 3) * 2 }
- MOV SI,[SI]
- MOV DI,DX
- SHR DI,1
- SHR DI,1
- ADD SI,DI
- ADD SI,[yoffset_] {SI = sprite[WORD PTR (licutoff_...)] }
- { + (lecutoff_in_points + i) DIV 4 }
- { + yoffset }
-
- {DI = destination pointer := (ScreenStartX + 0) DIV 4 + zeilenadr}
- MOV DI,AX {DI = ScreenStartX }
- SHR DI,1
- SHR DI,1
- ADD DI,BX
- MOV BL,AL
- AND BX,3 {BX = (ScreenStartX + i) AND 3 }
- MOV AH,Translate[BX] {AH = 1,2,4,8 for BX = 0,1,2,3 }
- MOV AL,2
- MOV DX,3C4h
- OUT DX,AX {choose plane }
-
- XCHG BX,DI
- {copy CX bytes from DS:SI to ES:BX }
- {this is the address where the data transfer routine will be patched!}
- @Patch1:
- db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-
- @Plane1:
- MOV DX,[bildx]
- INC DX {DX = ScreenStartX+1 }
- MOV BX,DX
- SHR BX,1
- SHR BX,1 {BX = destination pointer := (ScreenStartX + 1) }
- ADD BX,[zeilenadr] { DIV 4 + zeilenadr }
- MOV CX,BP
- DEC CX {CX = width of this line + 3 - 1 }
- SHR CX,1
- SHR CX,1 {CX = bytes_to_move for i = 1 }
- JCXZ @Plane2
- MOV DI,[licutoff_]
- INC DI {DI = (lecutoff_in_points + 1) }
- MOV SI,DI
- AND SI,3
- SHL SI,1 {SI = ((lecutoff_in_points + 1) AND 3) * 2 }
- MOV SI,[SI] {SI = sprite[WORD PTR licutoff_...] }
- SHR DI,1 { + (lecutoff_in_points + 1) DIV 4 }
- SHR DI,1 { + yoffset }
- ADD SI,DI
- ADD SI,[yoffset_] {SI = source pointer, }
- {DI = (lecutoff_in_points + 1) DIV 4 }
-
- MOV DI,DX {DI = ScreenStartX + 1 }
- AND DI,3 {DI = (ScreenStartX + 1) AND 3 }
- MOV AH,Translate[DI] {load mask for port-access }
- MOV AL,2
- MOV DX,3C4h {select plane }
- OUT DX,AX
-
- {this is the address where the data transfer routine will be patched!}
- @Patch2:
- db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-
- @Plane2:
- MOV DX,[bildx]
- ADD DX,2
- MOV BX,DX
- SHR BX,1
- SHR BX,1
- ADD BX,[zeilenadr]
- MOV CX,BP
- SUB CX,2
- SHR CX,1
- SHR CX,1
- JCXZ @Plane3
- MOV DI,[licutoff_]
- ADD DI,2
- MOV SI,DI
- AND SI,3
- SHL SI,1
- MOV SI,[SI]
- SHR DI,1
- SHR DI,1
- ADD SI,DI
- ADD SI,[yoffset_]
-
- MOV DI,DX {DI = ScreenStartX + 2 }
- AND DI,3 {DI = (ScreenStartX + 1) AND 3 }
- MOV AH,Translate[DI]
- MOV AL,2
- MOV DX,3C4h
- OUT DX,AX
-
- {this is the address where the data transfer routine will be patched!}
- @Patch3:
- db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-
- @Plane3:
- MOV DX,[bildx]
- ADD DX,3
- MOV BX,DX
- SHR BX,1
- SHR BX,1
- ADD BX,[zeilenadr]
- MOV CX,BP
- SUB CX,3
- SHR CX,1
- SHR CX,1
- JCXZ @Zeile_fertig
- MOV DI,[licutoff_]
- ADD DI,3
- MOV SI,DI
- AND SI,3
- SHL SI,1
- MOV SI,[SI]
- SHR DI,1
- SHR DI,1
- ADD SI,DI
- ADD SI,[yoffset_]
-
- MOV DI,DX {DI = ScreenStartX + 3 }
- AND DI,3 {DI = (ScreenStartX + 1) AND 3 }
- MOV AH,Translate[DI]
- MOV AL,2
- MOV DX,3C4h
- OUT DX,AX
-
- {this is the address where the data transfer routine will be patched!}
- @Patch4:
- db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-
- @Zeile_fertig:
- MOV AX,[yoffset_]
- @max_Breite:
- SUB AX,1234
- MOV [yoffset_],AX
- MOV BX,[zeilenadr]
- SUB BX,LINESIZE
- MOV [zeilenadr],BX
- SUB WORD PTR [end_min_start],2
- JS @Sprite_fertig
-
- @Starty_2:
- MOV DI,1234
- @akt_SpriteX:
- MOV BP,1234
- JMP @eine_Zeile
-
- @Sprite_fertig:
- POP SI
- MOV AX,SEG @Data
- MOV DS,AX
-
- @noSprite:
- DEC SI
- DEC SI
- JS @fertig
- JMP @zeichne
- @fertig:
-
- POP BP
-
- {reset Win* variables to their old values --if necessary: }
- MOV AX,SplitIndex
- CMP AX,NMAX
- JGE @skip {IF (SplitIndex<0) OR (SplitIndex>NMAX) THEN Skip}
-
- MOV AX,BWinLowerRight
- MOV WinLowerRight,AX
- MOV BX,BWinXMIN
- MOV WinXMIN,BX
- MOV SI,BX {SI := WinXMIN}
- SHR BX,1
- SHR BX,1
- MOV WinXMINdiv4,BX {BX := WinXMIN div 4}
- MOV CX,BWinYMIN
- MOV WinYMIN,CX {CX := WinYMIN}
- MOV AX,BWinYMIN_mul_LINESIZE
- MOV WinYMIN_mul_LINESIZE,AX
- ADD AX,BX
- MOV WinYMINmLINESIZEaWinXMINdiv4,AX
- MOV AX,BWinXMAX
- MOV WinXMAX,AX {AX := WinXMAX}
- MOV DX,BWinYMAX
- MOV WinYMAX,DX {DX := WinYMAX}
- SUB DX,CX
- INC DX
- MOV WinHeight,DX
- SUB AX,SI
- INC AX
- MOV WinWidth,AX
- SHR AX,1
- SHR AX,1
- MOV WinWidthDiv4,AL
- @skip:
-
- {prepare "CX := Offset_Adr[Page]": }
- MOV SI,PAGE {page value *2 (word-sized entries!)}
- MOV BX,SI {save page value in BX!}
- SHL SI,1 {add start address of array to that }
- ADD SI,OFFSET Offset_Adr-StartIndex*2 {evtl. correct displacement }
- LODSW {realize "AX := Offset_Adr[Page]" }
- MOV CX,AX {bring value to CX}
- MOV DI,CRTAddress {DI := CRTAddress }
-
- {The graphic page is now ready to be displayed: }
- cli
- mov dx,StatusReg
-
- {Wait for "display enable"=0 (that is: active), so that page flipping }
- {for HB/LB takes place while displaying the same page:}
-
- @WaitNotHSyncLoop:
- in al,dx
- and al,1
- jz @WaitNotHSyncLoop
-
- @WaitHSyncLoop:
- in al,dx
- and al,1
- jnz @WaitHSyncLoop
-
- MOV DX,DI {DX := CRTAddress}
- MOV AL,$0D {LB-startaddress-register}
- OUT DX,AL
- INC DX
-
- MOV AX,CX {AX := Offset_Adr[Page]}
- OUT DX,AL {set LB of new starting address }
- DEC DX
- MOV AL,$0C
- OUT DX,AL
- INC DX
- MOV AL,AH {set HB of new starting address }
- OUT DX,AL
- STI
-
- NEG BX {new PAGE-value := 1-old PAGE-value, that is: }
- ADD BX,1 {IF PAGE = 0 THEN PAGE := 1 ELSE (PAGE = 1) PAGE := 0 }
- MOV PAGE,BX
-
- SHL BX,1 {new PAGEADR-value := Segment_Adr[PAGE] }
- ADD BX,OFFSET Segment_Adr-StartIndex*2
- MOV AX,[BX]
- MOV PAGEADR,AX
-
- {Check whether the preset (min.) cycle time has passed: }
- @L10:
- MOV AL,TimeFlag {bit 7 = 0/1 for delay completed/not yet completed }
- AND AL,$80
- JE @L10
-
- {start time control mechanism for next cycle:}
- MOV AL,IsAT {is this an AT/386? ($0/$80 = yes/no) }
- OR AL,AL {timing mechanism only works on AT/386 }
- JNE @L11 {otherwise: no timing mechanism! }
- MOV TimeFlag,AL {AL = 0 use this as initial value, too }
- MOV DX,WORD PTR CycleTime {store min. time for 1 cycle (micro- }
- MOV CX,WORD PTR CycleTime+2 {seconds): CX = HIGH-word, DX = LOW-word }
- MOV BX,OFFSET TimeFlag {ES:BX = pointer to TimeFlag, bit 7 = 0/1}
- MOV AX,DS {for: delay still lasts/has ended }
- MOV ES,AX
- MOV AX,8300h {start time control mechanism}
- INT 15h
- @L11:
- END; {of ASM}
- END; {of ANIMATE}
-
- PROCEDURE FreeSpriteMem(number:WORD);
- { in: number = sprite load number of the sprite to deallocate }
- {out: allocated memory has been released, SPRITEAD[number] has been set to 0 and}
- { SPRITEPTR[number] has been set to NIL}
- {rem: sprite numbers referencing to the released sprite contents }
- { are not allowed after this routine, of course!}
- { If no sprite "number" had been loaded, nothing at all will happen}
- { evtl. sprite cycles must be freed by calling this routine for each}
- { of its members once. }
- BEGIN
- IF (number<1) OR (number>LoadMAX)
- THEN Error:=Err_InvalidSpriteLoadNumber
- ELSE IF SPRITEPTR[number]<>NIL
- THEN BEGIN
- FreeMem(SPRITEPTR[number],SPRITESIZE[number]);
- SPRITEPTR[number]:=NIL;
- SPRITESIZE[number]:=0;
- SPRITEAD[number]:=0
- END
- END;
-
- FUNCTION LoadSprite(name:String; number:WORD):WORD;
- { in: name = name of the sprite file to load (type: "*.COD" / "*.LIB") }
- { number = number for the first sprite of this file }
- {out: number of the sprites read in from the file (0 = error occured) }
- {The routine detects automatically, if the file holfds a single }
- { tains a single sprite or a complete sprite library and loads all }
- { sprite data onto the heap, in a way such that the address always }
- { lies on a segment (=paragraph) boundary. These starting addresses }
- { are then stored in table SPRITEAD[number]; if more than one sprite }
- { has been loaded, they will be stored with consecutive numbers, that }
- { is, number+i }
- LABEL quit_loop;
- VAR p1,p2:Pointer;
- f:FileOfByte;
- count:WORD;
- Header:SpriteHeader;
- tempName:STRING;
- BEGIN
- count:=0; {number of sprites already read in }
-
- tempName:=FindFile(name);
- IF tempName<>'' THEN name:=tempName;
-
- _assign(f,name);
- {$I-} _reset(f); {$IFDEF IOcheck} {$I+} {$ENDIF}
- if (ioresult<>0) OR (CompressError<>CompressErr_NoError)
- THEN BEGIN {File doesn't exist or at least not with that path }
- Error:=Err_FileIO;
- CompressError:=CompressErr_NoError;
- loadSprite:=0; exit
- END;
- IF (number=0) or (number>LoadMAX)
- THEN BEGIN
- Error:=Err_InvalidSpritenumber;
- goto quit_loop;
- END;
- WHILE NOT _physicalEOF(f) DO
- BEGIN
- {first, read in the sprite header: }
- {$I-} {load sprite header vià BLOCKREAD into the heap }
- _blockread(f,Header,Kopf);
- {$IFDEF IOcheck} {$I+} {$ENDIF}
-
- IF (ioresult<>0) OR (CompressError<>CompressErr_NoError)
- THEN BEGIN
- Error:=Err_FileIO;
- CompressError:=CompressErr_NoError;
- goto quit_loop;
- END;
- IF (Header.Kennung[1]<>'K') or (Header.Kennung[2]<>'R')
- THEN BEGIN
- Error:=Err_NoSprite;
- goto quit_loop;
- END;
- {enough space left? }
- IF (Header.SpriteLength+15>MaxAvail+SPRITESIZE[number+count])
- THEN BEGIN
- Error:=Err_NotEnoughMemory;
- goto quit_loop;
- END;
-
- FreeSpriteMem(number+count); {evtl. release old memory }
-
- {Now read in the real sprite data: }
- getmem(p1,Header.SpriteLength+15); {get enough space }
- SPRITESIZE[number+count]:=Header.SpriteLength+15;
- SPRITEPTR [number+count]:=p1;
- IF (LONGINT(p1) mod 16)=0
- THEN p2:=p1 {make p2 fall on segment boundary}
- ELSE LONGINT(p2):=LONGINT(p1) + (16-LONGINT(p1) mod 16);
-
- MOVE(Header,p2^,Kopf); {store sprite header to heap }
- LONGINT(p1):=LONGINT(p2)+Kopf; {points exactly behind the header}
-
- {$I-} {load the "rest" of the sprite }
- _blockread(f,p1^,Header.SpriteLength-Kopf);
- {$IFDEF IOcheck} {$I+} {$ENDIF}
- IF (ioresult<>0) OR (CompressError<>CompressErr_NoError)
- THEN BEGIN
- Error:=Err_FileIO;
- CompressError:=CompressErr_NoError;
- goto quit_loop;
- END;
-
- {assign it to the sprite number:}
- spritead[number+count]:=(longint(p2) shr 16)
- +(longint(p2) and 65535) shr 4;
- INC(count);
-
- IF (NOT _physicalEOF(f)) AND
- ( (NOT f.komprimiert) OR (_logicalEOF(f)) )
- THEN Resync(f)
- END;
-
- quit_loop: ;
- _close(f);
- loadSprite:=count
- END;
-
- FUNCTION LoadTile(name:STRING; number:BYTE):WORD;
- { in: name = name of the sprite file to load (type: "*.COD" / "*.LIB") }
- { number = 0..255 = tile number for the file's first sprite }
- {out: number of the tiles read in from the file (0 = error occured) }
- {The routine detects automatically, if the file holfds a single }
- { sprite or a complete sprite library. Always all sprites in the file }
- { sprites, splits them into tiles and stores them into the 4th graphic }
- { page, starting with the given number "number" }
- { Because a tile consists of 16x16 points, the sprites must be a mul- }
- { tiple of 16 points in each direction (x _and_ y) }
- { If the file contains more than one tile, they will be loaded by row, }
- { each row from left to right }
- LABEL quit_loop;
- TYPE split=RECORD loword,hiword:WORD END;
- VAR p1:Pointer;
- ad,p:LONGINT;
- f:FileOfByte;
- count,ZielOfs,step,yoffset:WORD;
- pSeg,pOfs:ARRAY[0..3] OF WORD;
- Breite_in_Tiles,Hoehe_in_Tiles,x,y,i,zeilen:BYTE;
- Header:SpriteHeader;
- tempName:STRING;
- BEGIN
- count:=0; {number of sprites already read in }
- tempName:=FindFile(name);
- IF tempName<>'' THEN name:=tempName;
- _assign(f,name);
- {$I-} _reset(f); {$IFDEF IOcheck} {$I+} {$ENDIF}
- if (ioresult<>0) OR (CompressError<>CompressErr_NoError)
- THEN BEGIN {File doesn't exist or at least not with that path }
- Error:=Err_FileIO;
- CompressError:=CompressErr_NoError;
- LoadTile:=0; exit
- END;
- WHILE NOT _physicalEOF(f) DO
- BEGIN
- {first, read in the sprite header: }
- {$I-} {load sprite header vià BLOCKREAD into the heap }
- _blockread(f,Header,Kopf);
- {$IFDEF IOcheck} {$I+} {$ENDIF}
-
- IF (ioresult<>0) OR (CompressError<>CompressErr_NoError)
- THEN BEGIN
- Error:=Err_FileIO;
- CompressError:=CompressErr_NoError;
- goto quit_loop;
- END;
- IF (Header.Kennung[1]<>'K') or (Header.Kennung[2]<>'R')
- THEN BEGIN
- Error:=Err_NoTile; {or Err_NoSprite! }
- goto quit_loop
- END;
- IF (Header.Breite_in_4er_Gruppen MOD 4<>0) OR
- (Header.Hoehe_in_Zeilen MOD 16<>0) {size a multiple of 16? }
- THEN BEGIN
- Error:=Err_NoTile;
- goto quit_loop
- END
- ELSE BEGIN {yes, get number of tiles in that sprite file }
- Breite_in_Tiles:=Header.Breite_in_4er_Gruppen SHR 2;
- Hoehe_in_Tiles :=Header.Hoehe_in_Zeilen SHR 4;
- step:=Breite_in_Tiles*4; {"step" needed for correct addressing}
- END;
- IF (Header.SpriteLength>MaxAvail) {enough space left? }
- THEN BEGIN
- Error:=Err_NotEnoughMemory;
- goto quit_loop;
- END;
-
- {Now read in the real sprite data: }
- getmem(p1,Header.SpriteLength); {get enough space }
-
- {$I-} {load the "rest" of the sprite }
- _blockread(f,p1^,Header.SpriteLength-Kopf);
- {$IFDEF IOcheck} {$I+} {$ENDIF}
- IF (ioresult<>0) OR (CompressError<>CompressErr_NoError)
- THEN BEGIN
- Error:=Err_FileIO;
- CompressError:=CompressErr_NoError;
- goto quit_loop;
- END;
-
- ad:=(LONGINT(split(p1).HiWord) SHL 4) + split(p1).LoWord - Kopf;
- FOR i:=0 TO 3 DO
- BEGIN
- p:=ad+Header.Zeiger_auf_Plane[i]; pSeg[i]:=p SHR 4; pOfs[i]:=p AND $F;
- END;
-
- FOR y:=0 TO Pred(Hoehe_in_Tiles) DO
- BEGIN
- yoffset:=y*Breite_in_Tiles*16*(16 DIV 4);
- FOR x:=0 TO Pred(Breite_in_Tiles) DO
- BEGIN
- IF count+number>255
- THEN BEGIN
- Error:=Err_InvalidTileNumber;
- goto quit_loop
- END;
- ZielOfs:=(number+count) SHL 6;
- FOR i:=0 TO 3 DO
- BEGIN
- PORTW[$3C4]:=(TranslateTab[i] SHL 8) + 2;
- FOR zeilen:=0 TO 15 DO
- BEGIN
- move(mem[pSeg[i]:pOfs[i] + yoffset + zeilen*step + x*(16 DIV 4)],
- mem[SCROLLADR:ZielOfs + zeilen*(16 DIV 4)],
- 16 DIV 4);
- END;
- END;
-
- INC(count);
- END;
- END;
- FreeMem(p1,Header.SpriteLength); {release memory }
- IF (NOT _physicalEOF(f)) AND
- ( (NOT f.komprimiert) OR (_logicalEOF(f)) )
- THEN Resync(f)
- END;
-
- quit_loop: ;
- _close(f);
- LoadTile:=count
- END;
-
- PROCEDURE SetBackgroundScrollRange(x1,y1,x2,y2:INTEGER);
- { in: (x1,y1) = upper left corner of the area (in virtual coord.)}
- { (x2,y2) = dto., lower right corner}
- {out: (BackX1,BackY1), (BackX2,BackY2) = coord., rounded to 16'grid }
- { XTiles, YTiles = width and height of the chosen range in tiles }
- {rem: The upper left corner will be torn to the upper left, the lower }
- { right corner to the lower right!}
- { Obviously, calling the routine only makes sense when using SCROLLING }
- { as background mode! }
- BEGIN
- BackX1:=x1 AND $FFF0; BackX2:=x2 OR $F;
- BackY1:=y1 AND $FFF0; BackY2:=y2 OR $F;
- xtiles:=succ(BackX2-BackX1) shr 4;
- ytiles:=succ(BackY2-BackY1) shr 4;
- IF (xtiles OR ytiles)<=0
- THEN Error:=Err_InvalidCoordinates
- ELSE IF xtiles*ytiles>MaxTiles
- THEN Error:=Err_BackgroundToBig;
- END;
-
- PROCEDURE SetBackgroundMode(mode:BYTE);
- { in: mode = wanted background mode, STATIC or SCROLLING }
- {out: Backgroundmode = set mode, STATIC/SCROLLING }
- BEGIN
- IF (mode<>STATIC) AND (mode<>SCROLLING)
- THEN Error:=Err_InvalidMode
- ELSE Backgroundmode:=mode
- END;
-
- PROCEDURE MakeTileArea(FirstTile:BYTE; TileWidth,TileHeight:INTEGER);
- { in: FirstTile = starting index of first tile }
- { TileWidth = width (in tiles) of the rectangular pattern to be repeated}
- { TileHeight= dto., height}
- { BackX1,BackY1,BackX2,BackY2= background area set by calling }
- { SetScrollRange() }
- {out: Starting with tile no. FirstTile, the next TileWidth*TileHeight }
- { tiles have been used as a repeating rectangular pattern of }
- { width TileWidth and height TileHeight into the background. }
- { This way, the complete defined background area has been built }
- { For example, MakeTileArea(7,3,2) will result in the following }
- { layout: }
- { ┌──┬──┬──┬──┬──┬──┬──┬ }
- { │ 7│ 8│ 9│ 7│ 8│ 9│ 7│... }
- { ├──┼──┼──┼──┼──┼──┼──┼ }
- { │10│11│12│10│11│12│10│... }
- { ├──┼──┼──┼──┼──┼──┼──┼ }
- { │ 7│ 8│ 9│ 7│ 8│ 9│ 7│... }
- { ├──┼──┼──┼──┼──┼──┼──┼ }
- { │10│11│12│10│11│12│10│... }
- { ├──┼──┼──┼──┼──┼──┼──┼ }
- { . . . . . . . }
- { . . . . . . . }
- {rem: Calling this routine only makes sense, when SCROLLING has been}
- { set as background mode and SetScrollRange() has been called }
- { previously!}
- VAR GY,StartRowTile,
- x,y:INTEGER;
- BEGIN
- IF (TileWidth>0) AND (TileHeight>0)
- THEN BEGIN
- FOR y:=0 TO ytiles-1 DO
- BEGIN
- gy:=BackY1+(y SHL 4); {y-coordinate for this row }
- {compute index of 1st tile of the actual row: }
- StartRowTile:=(y MOD TileHeight)*TileWidth+FirstTile;
- FOR x:=0 TO xtiles-1 DO
- PutTile(BackX1+(x SHL 4),gy,StartRowTile+(x MOD TileWidth));
- END
- END
-
- ELSE Error := Err_InvalidCoordinates
- END;
-
- PROCEDURE PutTile(x,y:INTEGER; TileNr:BYTE);
- { in: x,y = virtual coordinates where the tile shall be placed }
- { TileNr= number of the tile to be placed }
- {out: - }
- {rem: The point (x,y) first gets rounded to a grid with mesh 16 }
- { Calling this routine only makes sense when using SCROLLING}
- { as background mode! }
- VAR index:WORD;
- BEGIN
- ASM
- MOV AX,x {compute relative X-distance from left edge of }
- SUB AX,BackX1 {the defined area and store it to "x", formula: }
- SAR AX,1 { x := ((x AND $FFF0) - BackX1) DIV 16 (nicht: }
- SAR AX,1 {SHR 4)! "AND $FFF0" kann dabei entfallen, da in}
- SAR AX,1 {BackX1 last hex-digit is $0! }
- SAR AX,1
- MOV x,AX
-
- MOV AX,y {dto. for distance between the y-coordinate and }
- SUB AX,BackY1 {the upper edge: y := ((y AND $FFF0) - BackY1) DIV 16 }
- SAR AX,1
- SAR AX,1
- SAR AX,1
- SAR AX,1
- MOV y,AX
- END;
-
- IF (x<0) OR (x>=XTiles) OR (y<0) OR (y>=YTiles)
- THEN Error:=Err_InvalidCoordinates
- ELSE BEGIN {a tile row has width XTiles, each tile consists of 16x16 points}
- index:=y*XTiles+x; {to be exact: (x MOD XTiles)}
- BackTile[Succ(index)]:=TileNr; {"succ", to hold free BackTile[0] }
- END;
- END;
-
- FUNCTION GetTile(x,y:INTEGER):BYTE;
- { in: x,y = virtual coordinate for which the corresp. tile should be computed}
- {out: no. of the tile at this position }
- {rem: The point (x,y) first gets rounded to a grid with mesh 16}
- { If the point lies outside the defined scroll area, then the }
- { routine returns the value BackTile[0] of the offscreen tile}
- BEGIN
- ASM
- MOV AX,x {compute relative X-distance from left edge of }
- SUB AX,BackX1 {the defined area and store it to "x", formula: }
- SAR AX,1 { x := ((x AND $FFF0) - BackX1) DIV 16 (nicht: }
- SAR AX,1 {SHR 4)! "AND $FFF0" kann dabei entfallen, da in}
- SAR AX,1 {BackX1 last hex-digit is $0! }
- SAR AX,1
- MOV x,AX
-
- MOV AX,y {dto. for distance between the y-coordinate and }
- SUB AX,BackY1 {the upper edge: y := ((y AND $FFF0) - BackY1) DIV 16 }
- SAR AX,1
- SAR AX,1
- SAR AX,1
- SAR AX,1
- MOV y,AX
- END;
-
- IF (x<0) OR (x>=XTiles) OR (y<0) OR (y>=YTiles)
- THEN GetTile:=BackTile[0]
- ELSE GetTile:=BackTile[y*XTiles+x+1]
- END;
-
- PROCEDURE SetOffscreenTile(TileNr:BYTE);
- { in: TileNr= number of the tile to be placed }
- {out: - }
- {rem: all screen parts, which lie outside the window specified by }
- { SetBackgroundScrollRange will become the tile TileNr as }
- { pattern }
- { Calling this routine only makes sense when using SCROLLING }
- { as background mode! }
- BEGIN
- BackTile[0]:=TileNr
- END;
-
- PROCEDURE SetModeByte(Sp:WORD; M:BYTE);
- { in: Sp = spriteLOADnumber, which mode byte shall be changed }
- {out: M = method, which shall be used to display Sp from now on: }
- { Display_NORMAL, Display_FAST, Display_SHADOW or }
- { Display_SHADOWEXACT }
- {rem: If the sprite doesn't exist yet (or the mode isn't allowed), }
- { nothing will happen at all }
- VAR ad:WORD;
- BEGIN
- ad:=SPRITEAD[Sp];
- IF ad=0 THEN Error:=Err_InvalidSpriteNumber {sprite must already be loaded}
- ELSE IF (M<Display_NORMAL) OR (M>Display_SHADOWEXACT)
- THEN Error:=Err_InvalidMode {only these 4 modes are allowed}
- ELSE MEM[ad:Modus]:=M
- END;
-
- FUNCTION GetModeByte(Sp:WORD):BYTE;
- { in: Sp = spriteLOADnumber, which mode byte shall be determined }
- {out: actually set display method for sprite Sp: Display_NORMAL, }
- { Display_FAST, Display_SHADOW, Display_SHADOWEXACT or }
- { Display_UNKNOW, if the sprite hasn't been loaded, yet! }
- VAR ad:WORD;
- BEGIN
- ad:=SPRITEAD[Sp];
- IF (ad=0)
- THEN GetModeByte:=Display_UNKNOWN {sprite not yet loaded }
- ELSE GetModeByte:=MEM[SPRITEAD[Sp]:Modus]
- END;
-
- PROCEDURE FillBackground(color:BYTE);
- { in: color = color for filling the background page BACKGNDPAGE }
- { BACKGNDADR = pointer to background memory }
- {out: The graphic page BACKGNDPAGE has been filled with color "Color"}
- {rem: Using the routine only makes sense when using background mode STATIC }
- BEGIN
- IF EMSused
- THEN EMSFillFrame(BackgroundEMSHandle); {prepare EMS access }
- FillChar(MEM[BACKGNDADR:0],4*PAGESIZE,color);
- END;
-
- PROCEDURE FillPage(pa:WORD; color:BYTE);
- { in: pa = the page which shall be filled (0..3) }
- { color = color with which to fill the page}
- {out: graphic page "pa" has been filled with color "Color"}
- {rem: It only makes sense to use pages 0,1 and BACKGNDPAGE, }
- { but SCROLLPAGE is allowed, too }
- BEGIN
- IF (pa<0) OR (pa>SCROLLPAGE)
- THEN Error:=Err_InvalidPageNumber
- ELSE IF pa=BACKGNDPAGE
- THEN FillBackground(color)
- ELSE BEGIN
- portw[$3C4]:=$0F02; {use MapMask register to select all 4 planes }
- fillchar(MEM[Segment_Adr[pa]:0],PAGESIZE,Color)
- END;
- END;
-
- PROCEDURE GetBackgroundFromPage(pa:WORD);
- {in : pa = 0 or 1 }
- {out: - }
- {The background memory BACKGNDPAGE becomes filles with the contents of the }
- { specified graphic page. }
- { Using the routine only makes sense when using background mode STATIC}
- VAR p:POINTER;
- BEGIN
- IF (pa<>0) AND (pa<>1) AND (pa<>SCROLLPAGE)
- THEN Error:=Err_InvalidPageNumber
- ELSE BEGIN
- IF EMSused
- THEN EMSFillFrame(BackgroundEMSHandle); {prepare EMS access }
- ASM
- MOV ES,BACKGNDADR
- MOV SI,pa
- SHL SI,1
- ADD SI,OFFSET Segment_Adr-StartIndex*2
- LODSW
- MOV DS,AX
- XOR SI,SI
- XOR DI,DI
-
- MOV DX,3CEh
- MOV AX,0004h {plane to read from 0}
- MOV BX,PAGESIZE / 2
-
- {DS:SI = source pointer, ES:DI = destination pointer, BX = no. of words }
- {AX = access mask for read plane 0, DX = port address for it}
-
- CLI
- OUT DX,AX {select plane 0 }
- MOV CX,BX
- REP MOVSW {store plane data }
- XOR SI,SI {reset SI }
-
- INC AH {select plane 1 }
- OUT DX,AX
- MOV CX,BX
- REP MOVSW
- XOR SI,SI
-
- INC AH {select plane 2 }
- OUT DX,AX
- MOV CX,BX
- REP MOVSW
- XOR SI,SI
-
- INC AH {select plane 3 }
- OUT DX,AX
- MOV CX,BX
- REP MOVSW
-
- STI
- MOV AX,SEG @DATA
- MOV DS,AX
- END
- END;
- END;
-
- PROCEDURE WritePage(name:STRING; pa:WORD);
- { in: name = file name for the picture to store }
- { pa = page to be saved (0..3) }
- { PAGESIZE = size of one bitplane }
- { PICHeader= tag for picture file }
- {out: - }
- {rem: The picture at page "pa" has been stored (as bitmap) to file "name" }
- { This file has size 4*PAGESIZE+3 = 64003 bytes: 320x200 points , }
- { 1 byte plus length(PICHeader) as tag }
- VAR f:FILE;
- i,oldMode:BYTE;
- fehler:BOOLEAN;
- BEGIN
- IF (pa<0) OR (pa>SCROLLPAGE)
- THEN BEGIN
- Error:=Err_InvalidPageNumber; exit
- END;
- {$I-}
- Assign(f,name); fehler:=IOResult<>0;
- Rewrite(f,1); fehler:=fehler OR (IOResult<>0);
- BlockWrite(f,PICHeader[1],Length(PICHeader));
- fehler:=fehler OR (IOResult<>0);
- {$IFDEF IOcheck} {$I+} {$ENDIF}
- IF fehler
- THEN BEGIN
- {$I-} Close(f); {$IFDEF IOcheck} {$I+} {$ENDIF}
- Error:=Err_FileIO; exit
- END;
-
- IF pa<>BACKGNDPAGE
- THEN BEGIN {VRAM to disk }
- port[$3ce]:=5; {save old read-/write mode }
- oldMode:=port[$3cf];
- port[$3cf]:=$40; {set read mode 0 }
- FOR i:=0 TO 3 DO
- BEGIN
- portw[$3CE]:=4+(i shl 8); {select read plane }
- {$I-}
- BlockWrite(f,mem[Segment_Adr[pa]:0],PAGESIZE);
- {$IFDEF IOcheck} {$I+} {$ENDIF}
- fehler:=fehler OR (IOResult<>0);
- END;
- port[$3ce]:=5; {restore old read-/write mode }
- port[$3cf]:=oldMode;
- END
- ELSE BEGIN {RAM to disk }
- IF EMSused
- THEN EMSFillFrame(BackgroundEMSHandle); {prepare EMS access }
- FOR i:=0 TO 3 DO
- BEGIN
- {$I-}
- BlockWrite(f,MEM[BACKGNDADR:BACKtab[i]],PAGESIZE);
- {$IFDEF IOcheck} {$I+} {$ENDIF}
- fehler:=fehler OR (IOResult<>0);
- END
- END;
- {$I-}
- Close(f);
- {$IFDEF IOcheck} {$I+} {$ENDIF}
- fehler:=fehler OR (IOResult<>0);
- IF fehler THEN Error:=Err_FileIO
- END;
-
- PROCEDURE LoadPage(name:STRING; pa:WORD);
- { in: name = file name for the picture to load}
- { pa = destination page to which the image shall be loaded (0..3) }
- { PAGESIZE = size of one bitplane }
- { PICHeader= tag for picture files }
- {out: - }
- {rem: The bitmap-picture in file "name" has been loaded into page "pa" }
- VAR f:FileOfByte;
- i,oldMode:BYTE;
- fehler:BOOLEAN;
- s:STRING[3];
- splane:WORD;
- p1,p2:POINTER;
- tempName:STRING;
- TYPE tempArray=ARRAY[1..PAGESIZE] OF BYTE;
- VAR temp:^tempArray;
- BEGIN
- IF (pa<0) OR (pa>SCROLLPAGE)
- THEN BEGIN
- Error:=Err_InvalidPageNumber; exit
- END;
- tempName:=FindFile(name);
- IF tempName<>'' THEN name:=tempName;
- {$I-}
- _Assign(f,name); fehler:=IOResult<>0;
- _Reset(f); fehler:=fehler OR (IOResult<>0);
- s[0]:=PICHeader[0];
- _BlockRead(f,s[1],Length(PICHeader));
- fehler:=fehler OR (IOResult<>0) OR (CompressError<>CompressErr_NoError);
- {$IFDEF IOcheck} {$I+} {$ENDIF}
- IF fehler
- THEN BEGIN
- {$I-} _Close(f); {$IFDEF IOcheck} {$I+} {$ENDIF}
- Error:=Err_FileIO;
- CompressError:=CompressErr_NoError;
- exit
- END
- ELSE IF (_FileSize(f)<>4*PAGESIZE+Length(PICHeader)) OR (s<>PICHeader)
- THEN BEGIN
- {$I-} _Close(f); {$IFDEF IOcheck} {$I+} {$ENDIF}
- Error:=Err_NoPicture;
- exit
- END;
-
- IF pa<>BACKGNDPAGE
- THEN BEGIN {disk to VRAM }
- ASM cli END;
- port[$3ce]:=5; {save old read-/write mode }
- oldMode:=port[$3cf];
- New(temp);
- ASM sti END;
- FOR i:=0 TO 3 DO
- BEGIN
- {$I-}
- _BlockRead(f,temp^[1],PAGESIZE);
- {$IFDEF IOcheck} {$I+} {$ENDIF}
- fehler:=fehler OR (IOResult<>0);
- splane:=2+(TranslateTab[i] shl 8); {which write plane }
- p1:=@temp^[1];
- p2:=ptr(Segment_Adr[pa],0);
- ASM
- cli
- mov dx,$3CE {select write mode 0 }
- mov ax,$4005
- out dx,ax
-
- mov ax,splane {select write plane }
- mov dx,$3C4
- out dx,ax
-
- les di,p2
- lds si,p1
- mov cx,PAGESIZE SHR 1
- rep movsw
-
- mov ax,SEG @DATA
- mov ds,ax
- sti
- END;
-
- END;
- portw[$3ce]:=oldMode SHL 8 + 5; {restore old read-/write mode }
- Dispose(temp);
- END
- ELSE BEGIN {disk to RAM }
- IF EMSused
- THEN EMSFillFrame(BackgroundEMSHandle); {prepare EMS access }
- FOR i:=0 TO 3 DO
- BEGIN
- {$I-}
- _BlockRead(f,MEM[BACKGNDADR:BACKtab[i]],PAGESIZE);
- {$IFDEF IOcheck} {$I+} {$ENDIF}
- fehler:=fehler OR (IOResult<>0);
- END
- END;
- {$I-}
- _Close(f);
- {$IFDEF IOcheck} {$I+} {$ENDIF}
- fehler:=fehler OR (IOResult<>0) OR (CompressError<>CompressErr_NoError);
- IF fehler THEN Error:=Err_FileIO
- END;
-
- PROCEDURE WriteBackgroundPage(name:STRING);
- { in: name = file name for the background picture to store }
- { BACKGNDPAGE= page to be saved (=2) }
- { PAGESIZE = size of one bitplane }
- { PICHeader = tag for picture file }
- {out: - }
- {rem: The picture of the background page has been stored as file "name" }
- { This file has size 4*PAGESIZE+3 = 64003 bytes: 320x200 points }
- { at 1 byte each, plus length(PICHeader) as tag }
- { Using the routine only makes sense when using background mode STATIC }
- BEGIN
- WritePage(name,BACKGNDPAGE)
- END;
-
- PROCEDURE LoadBackgroundPage(name:STRING);
- { in: name = file name for the background picture to load}
- { BACKGNDPAGE= destination page, in which to load the picture (=2) }
- { PAGESIZE = size of one bitplane }
- { PICHeader= tag for picture files }
- {out: - }
- {rem: The bitmap-picture contained in file "name" has been loaded to the }
- { background page BACKGNDPAGE}
- { Using the routine only makes sense when using background mode STATIC}
- BEGIN
- LoadPage(name,BACKGNDPAGE)
- END;
-
- PROCEDURE FadeIn(pa,ti,style:WORD);
- { in: pa = page which shall be faded onto the actually visible page }
- { ti = time in milliseconds for this action }
- { style = algorithm which shall be used }
- { 1-PAGE = actually visible page }
- {out: Error = Err_InvalidFade, if illegal "style" value has been used }
- {rem: graphic mode must have been initialized already }
- { most often, you will use pa=BACKGNDPAGE }
-
- PROCEDURE WipeIn(pa,time:WORD);
- { in: pa = page, which contents will be made visible }
- { time = time (in millisceconds) for this action (approx.) }
- { 1-PAGE= (visible) graphic page on which to draw }
- {out: - }
- {rem: the contents of page "pa" has been copied to page 1-PAGE }
- CONST hoehe =40; {divisor of Succ(YMAX)}
- breite=40; {divisor of Succ(XMAX)}
- br_x =Succ(XMAX) DIV breite; {blocks in X-direction}
- br_y =Succ(YMAX) DIV hoehe; {blocks in Y-direction}
- n=hoehe*br_x; {number of executions of the delay loop }
- VAR i,x,y,ploty,plotx:WORD;
- counter:WORD;
- ClockTicks:LONGINT ABSOLUTE $40:$6C;
- t:LONGINT;
- temp:REAL;
- p:POINTER;
- BEGIN
- t:=ClockTicks;
- counter:=0;
- temp:=0.0182*time/n;
- FOR i:=0 TO pred(hoehe) DO
- FOR x:=0 TO pred(br_x) DO
- BEGIN
- FOR y:=0 TO pred(br_y) DO
- BEGIN
- IF ODD(x)
- THEN ploty:=y*hoehe+i +StartVirtualY
- ELSE ploty:=y*hoehe+(hoehe-1-i)+StartVirtualY;
- plotx:=x*breite +StartVirtualX;
- p:=GetImage(plotx,ploty,plotx+pred(breite),ploty,pa);
- PutImage(plotx,ploty,p,1-PAGE);
- FreeImageMem(p);
- END; {of FOR y}
- INC(counter);
- WHILE ClockTicks<t+counter*temp DO BEGIN END;
- END; {of FOR x}
- END;
-
- PROCEDURE Chaos(pa,time:WORD;m:BYTE);
- { in: pa = page, which contents will be made visible }
- { time = time (in millisceconds) for this action (approx.) }
- { m = the way how this shall be done (1..14)}
- { 1-PAGE= (visible) graphic page on which to draw }
- {out: - }
- {rem: the contents of page "pa" has been copied to page 1-PAGE }
- CONST n=Succ(XMAX)*Succ(YMAX); {number of screen pixels}
- {e.g., good values are sums of powers of 2 +1 }
- para:ARRAY[1..14] OF WORD=
- (13477,65,337,129,257,513,769,1025,481,4097,5121,177,16385,16897);
- VAR i,k,x,y:WORD;
- counter:WORD;
- ClockTicks:LONGINT ABSOLUTE $40:$6C;
- t:LONGINT;
- temp:REAL;
- rand:WORD;
- BEGIN
- t:=ClockTicks;
- counter:=0;
- rand:=0;
- IF (m<1) OR (m>14) THEN m:=1;
- k:=para[m];
- temp:=0.0182*time/n;
- FOR i:=0 TO 65535 DO
- BEGIN
- ASM {compute: "x := rand MOD 320" and "y := rand DIV 320" }
- XOR DX,DX
- MOV AX,rand
- MOV BX,XMAX+1
- DIV BX
- MOV y,AX
- MOV x,DX
- END;
- IF y<=YMAX
- THEN PutPixel(StartVirtualX+x,StartVirtualY+y,
- PageGetPixel(StartVirtualX+x,StartVirtualY+y,pa));
- ASM {compute: rand:=rand*k+1 }
- MOV AX,rand
- MUL k
- INC AX
- MOV rand,AX
- END;
- INC(counter);
- WHILE ClockTicks<t+counter*temp DO BEGIN END;
- END; {of FOR i}
- END;
-
- PROCEDURE Chaos2(pa,time:WORD;m:BYTE);
- { in: pa = page, which contents will be made visible }
- { time = time (in millisceconds) for this action (approx.) }
- { m = the way how this shall be done (1..1)}
- { 1-PAGE= (visible) graphic page on which to draw }
- {out: - }
- {rem: the contents of page "pa" has been copied to page 1-PAGE }
- CONST n=Succ(XMAX)*Succ(YMAX); {number of screen pixels}
- para:ARRAY[1..1] OF WORD=
- (39551);
- VAR i,k,x,y:WORD;
- counter:WORD;
- ClockTicks:LONGINT ABSOLUTE $40:$6C;
- t:LONGINT;
- temp:REAL;
- rand:WORD;
- BEGIN
- t:=ClockTicks;
- counter:=0;
- rand:=0;
- IF (m<1) OR (m>1) THEN m:=1;
- k:=para[m];
- temp:=0.0182*time/n;
- FOR i:=0 TO 65535 DO
- BEGIN
- ASM {compute: "x:=rand MOD 320" and "y:=rand DIV 320" }
- XOR DX,DX
- MOV AX,rand
- MOV BX,XMAX+1
- DIV BX
- MOV y,AX
- MOV x,DX
- END;
- PutPixel(StartVirtualX+x,StartVirtualY+y,
- PageGetPixel(StartVirtualX+x,StartVirtualY+y,pa));
- ASM {compute: rand:=(rand+k) MOD n }
- XOR DX,DX
- MOV AX,rand
- ADD AX,k
- JNC @normal
- ADD AX,(65536-n) {overflow, thus correct it }
- @normal:
- CMP AX,n
- JB @ok
- SUB AX,n
- @ok:
- MOV rand,AX
- END;
- INC(counter);
- WHILE ClockTicks<t+counter*temp DO BEGIN END;
- END; {of FOR i}
- END;
-
- PROCEDURE SweepVertical(pa,time:WORD; down:BOOLEAN);
- { in: pa = page, which contents will be made visible }
- { time = time (in millisceconds) for this action (approx.) }
- { down = TRUE/FALSE for: from bottom to top/vice versa }
- { 1-PAGE= (visible) graphic page on which to draw }
- {out: - }
- {rem: the contents of page "pa" has been copied to page 1-PAGE }
- CONST n=Succ(YMAX); {number of executions of the delay loop }
- VAR y,counter:WORD;
- ClockTicks:LONGINT ABSOLUTE $40:$6C;
- t:LONGINT;
- temp:REAL;
- oldColor,step:BYTE;
- p:POINTER;
- BEGIN
- oldColor:=Color;
- Color:=white;
- t:=ClockTicks;
- counter:=0;
- temp:=0.0182*time/n;
- IF down
- THEN FOR y:=0+StartVirtualY TO YMAX+StartVirtualY DO
- BEGIN
- Line(StartVirtualX,y,StartVirtualX+XMAX,y,1-PAGE);
- INC(counter);
- WHILE ClockTicks<t+counter*temp DO BEGIN END;
- p:=GetImage(StartVirtualX,y,StartVirtualX+XMAX,y,pa);
- PutImage(StartVirtualX,y,p,1-PAGE);
- FreeImageMem(p);
- END
- ELSE FOR y:=YMAX+StartVirtualY DOWNTO 0+StartVirtualY DO
- BEGIN
- Line(StartVirtualX,y,StartVirtualX+XMAX,y,1-PAGE);
- INC(counter);
- WHILE ClockTicks<t+counter*temp DO BEGIN END;
- p:=GetImage(StartVirtualX,y,StartVirtualX+XMAX,y,pa);
- PutImage(StartVirtualX,y,p,1-PAGE);
- FreeImageMem(p);
- END;
- Color:=oldColor
- END;
-
- PROCEDURE SweepHorizontal(pa,time:WORD; left_to_right:BOOLEAN);
- { in: pa = page, which contents will be made visible }
- { time = time (in millisceconds) for this action (approx.) }
- { left_to_right=TRUE/FALSE for: from left to right/vice versa }
- { 1-PAGE= (visible) graphic page on which to draw }
- {out: - }
- {rem: the contents of page "pa" has been copied to page 1-PAGE }
- CONST n=Succ(XMAX); {number of executions of the delay loop }
- VAR x,counter:WORD;
- ClockTicks:LONGINT ABSOLUTE $40:$6C;
- t:LONGINT;
- temp:REAL;
- oldColor,step:BYTE;
- p:POINTER;
- BEGIN
- oldColor:=Color;
- Color:=white;
- t:=ClockTicks;
- counter:=0;
- temp:=0.0182*time/n;
- IF left_to_right
- THEN FOR x:=0+StartVirtualX TO XMAX+StartVirtualX DO
- BEGIN
- Line(x,StartVirtualY,x,StartVirtualY+YMAX,1-PAGE);
- INC(counter);
- WHILE ClockTicks<t+counter*temp DO BEGIN END;
- p:=GetImage(x,StartVirtualY,x,StartVirtualY+YMAX,pa);
- PutImage(x,StartVirtualY,p,1-PAGE);
- FreeImageMem(p);
- END
- ELSE FOR x:=XMAX+StartVirtualX DOWNTO 0+StartVirtualX DO
- BEGIN
- Line(x,StartVirtualY,x,StartVirtualY+YMAX,1-PAGE);
- INC(counter);
- WHILE ClockTicks<t+counter*temp DO BEGIN END;
- p:=GetImage(x,StartVirtualY,x,StartVirtualY+YMAX,pa);
- PutImage(x,StartVirtualY,p,1-PAGE);
- FreeImageMem(p);
- END;
- Color:=oldColor
- END;
-
- PROCEDURE ScrollVertical(pa,time:WORD; up:BOOLEAN);
- { in: pa = page, which contents will be made visible }
- { time = time (in millisceconds) for this action (approx.) }
- { up = TRUE/FALSE for: from bottom to top/vice versa }
- { 1-PAGE= (visible) graphic page on which to draw }
- {out: - }
- {rem: the contents of page "pa" has been copied to page 1-PAGE }
- LABEL oneLine1,oneLine2,oneLine3,oneLine4;
- CONST n=Succ(YMAX); {number of executions of the delay loop }
- VAR counter:WORD;
- ClockTicks:LONGINT ABSOLUTE $40:$6C;
- t:LONGINT;
- temp:REAL;
- BEGIN
- t:=ClockTicks;
- counter:=0;
- temp:=0.0182*time/n;
- IF pa<>BACKGNDPAGE
- THEN BEGIN
- IF up
- THEN BEGIN {scroll upwards }
- ASM
- MOV DX,3C4h
- MOV AX,0F02h {access all 4 planes at once }
- OUT DX,AX
- MOV DX,3CEh
- MOV AX,4105h {set write mode 1 }
- OUT DX,AX
-
- MOV SI,1
- SUB SI,PAGE
- AND SI,1
- SHL SI,1
- ADD SI,OFFSET Segment_Adr-StartIndex*2
- LODSW
- MOV ES,AX {ES := Segment_Adr[1 - PAGE] = ^visible page }
-
- MOV SI,pa
- AND SI,3
- SHL SI,1
- ADD SI,OFFSET Segment_Adr-StartIndex*2
- LODSW {AX := Segment_Adr[pa] = ^source address}
-
- PUSH DS
- MOV DX,AX
- MOV BX,YMAX*LINESIZE+(LINESIZE-1) {DX:BX = ^source data}
-
- MOV AX,YMAX {AX = row counter }
-
- oneLine2:
- STD {move backwards! }
- MOV SI,ES {first scroll old contents upwards: }
- MOV DS,SI {DS = ES = visible graphic page }
- MOV SI,(YMAX-1)*LINESIZE+(LINESIZE-1) {from last but one graphic row}
- MOV DI,YMAX*LINESIZE+(LINESIZE-1) {to last graphic row }
- MOV CX,YMAX*LINESIZE {199 rows }
- REP MOVSB
-
- MOV DS,DX {now make new row visible: }
- MOV SI,BX {DS:SI = ^row to move }
- MOV CX,LINESIZE {1 row }
- REP MOVSB
-
- SUB BX,LINESIZE {increase source pointer }
-
- {--- insertion to realize timing:}
- PUSH AX {save all registers needed later }
- PUSH BX
- PUSH DX
- PUSH ES
- MOV AX,SEG @DATA {restore TP's data segment }
- MOV DS,AX
- CLD {just to be sure! }
- END;
- INC(counter);
- WHILE ClockTicks<t+counter*temp DO BEGIN END;
- ASM;
- POP ES
- POP DX
- POP BX
- POP AX
- {--- end of insertion}
-
- DEC AX {all rows done? }
- JNS oneLine2 {no, next row }
-
- MOV DX,3CEh {restore write mode 0 }
- MOV AX,4005h
- OUT DX,AX
- POP DS
- END;
- END
- ELSE BEGIN {scroll downwards }
- ASM
- MOV DX,3C4h
- MOV AX,0F02h {access all 4 planes at once }
- OUT DX,AX
- MOV DX,3CEh
- MOV AX,4105h {set write mode 1 }
- OUT DX,AX
-
- MOV SI,1
- SUB SI,PAGE
- AND SI,1
- SHL SI,1
- ADD SI,OFFSET Segment_Adr-StartIndex*2
- LODSW
- MOV ES,AX {ES := Segment_Adr[1-PAGE] = ^visible page }
-
- MOV SI,pa
- AND SI,3
- SHL SI,1
- ADD SI,OFFSET Segment_Adr-StartIndex*2
- LODSW {AX := Segment_Adr[pa] = ^source address}
-
- PUSH DS
- MOV DX,AX
- MOV BX,0*LINESIZE {DX:BX = ^source data}
-
- MOV AX,YMAX {AX = row counter }
-
- oneLine1:
- MOV SI,ES {first scroll old contents upwards: }
- MOV DS,SI {DS = ES = visible graphic page }
- MOV SI,1*LINESIZE {from graphic row 1}
- MOV DI,0*LINESIZE {to graphic row 0 }
- MOV CX,YMAX*LINESIZE {199 rows }
- REP MOVSB
-
- MOV DS,DX {now make new row visible: }
- MOV SI,BX {DS:SI = ^row to move }
- MOV CX,LINESIZE {1 row }
- REP MOVSB
-
- ADD BX,LINESIZE {increase source pointer }
-
- {--- insertion to realize timing:}
- PUSH AX {save all registers needed later }
- PUSH BX
- PUSH DX
- PUSH ES
- MOV AX,SEG @DATA {restore TP's data segment }
- MOV DS,AX
- END;
- INC(counter);
- WHILE ClockTicks<t+counter*temp DO BEGIN END;
- ASM;
- POP ES
- POP DX
- POP BX
- POP AX
- {--- end of insertion}
-
- DEC AX {all rows done? }
- JNS oneLine1 {no, next row }
-
- MOV DX,3CEh {restore write mode 0 }
- MOV AX,4005h
- OUT DX,AX
- POP DS
- END;
- END;
- END
-
- ELSE BEGIN {pa = BACKGNDPAGE, thus copy from RAM to VRAM}
- IF EMSused
- THEN EMSFillFrame(BackgroundEMSHandle); {prepare EMS access }
- IF up
- THEN BEGIN {scroll upwards }
- ASM
- MOV DX,3C4h
- MOV AX,0F02h {access all 4 planes at once }
- OUT DX,AX
-
- MOV SI,1
- SUB SI,PAGE
- AND SI,1
- SHL SI,1
- ADD SI,OFFSET Segment_Adr-StartIndex*2
- LODSW
- MOV ES,AX {ES := Segment_Adr[1 - PAGE] = ^visible page }
-
- PUSH DS
-
- MOV SI,pa
- AND SI,3
- SHL SI,1
- ADD SI,OFFSET Segment_Adr-StartIndex*2
- LODSW {AX := Segment_Adr[pa] = ^source address }
- {(for pa=BACKGNDPAGE id. to BACKGNADR)}
- PUSH BP
-
- MOV BP,AX
- MOV BX,YMAX*LINESIZE+(LINESIZE-1)-1 {BP:BX = ^source data}
-
- MOV AX,YMAX {AX = row counter }
-
- oneLine4:
- MOV SI,AX
- MOV DX,3CEh
- MOV AX,4105h {set write mode 1 }
- OUT DX,AX
- MOV AX,SI
-
- STD {move backwards! }
- MOV SI,ES {first scroll old contents upwards: }
- MOV DS,SI {DS = ES = visible graphic page }
- MOV SI,(YMAX-1)*LINESIZE+(LINESIZE-1) {from last but one graphic row}
- MOV DI,YMAX*LINESIZE+(LINESIZE-1) {to last graphic row }
- MOV CX,YMAX*LINESIZE {199 rows }
- REP MOVSB
-
- PUSH AX
- MOV DX,3CEh {select write mode 0}
- MOV AX,4005h
- OUT DX,AX
-
- MOV DX,3C4h
- MOV AX,0102h {select write plane 0 }
- OUT DX,AX
- MOV DS,BP {now make new row visible: }
- MOV SI,BX {DS:SI = ^row to move }
- DEC DI {decrement DI by 1 (word accesses!) }
- MOV CX,LINESIZE / 2 {1 row }
- REP MOVSW
-
- SHL AH,1 {select write plane 1 }
- OUT DX,AX
- ADD SI,PAGESIZE+LINESIZE
- MOV CX,LINESIZE / 2 {1 row }
- ADD DI,LINESIZE
- REP MOVSW
-
- SHL AH,1 {select write plane 2 }
- OUT DX,AX
- ADD SI,PAGESIZE+LINESIZE
- MOV CX,LINESIZE / 2 {1 row }
- ADD DI,LINESIZE
- REP MOVSW
-
- SHL AH,1 {select write plane 3 }
- OUT DX,AX
- ADD SI,PAGESIZE+LINESIZE
- MOV CX,LINESIZE / 2 {1 row }
- ADD DI,LINESIZE
- REP MOVSW
-
- MOV AH,$F {select all 4 planes }
- OUT DX,AX
-
- SUB BX,LINESIZE {increase source pointer }
- POP AX
-
- {--- insertion to realize timing:}
- MOV SI,BP {temporary BP }
- POP BP {TP's old BP }
- PUSH AX {save all registers needed later }
- PUSH BX
- PUSH SI
- PUSH ES
- MOV AX,SEG @DATA {restore TP's data segment }
- MOV DS,AX
- END;
- INC(counter);
- WHILE ClockTicks<t+counter*temp DO BEGIN END;
- ASM;
- POP ES
- POP SI
- POP BX
- POP AX
- PUSH BP
- MOV BP,SI
- {--- end of insertion}
-
- DEC AX {all rows done? }
- JNS oneLine4 {no, next row }
-
- POP BP
- POP DS
- END;
- END
- ELSE BEGIN {scroll downwards }
- ASM
- MOV DX,3C4h
- MOV AX,0F02h {access all 4 planes at once }
- OUT DX,AX
-
- MOV SI,1
- SUB SI,PAGE
- AND SI,1
- SHL SI,1
- ADD SI,OFFSET Segment_Adr-StartIndex*2
- LODSW
- MOV ES,AX {ES := Segment_Adr[1-PAGE] = ^visible page }
-
- PUSH DS
-
- MOV SI,pa
- AND SI,3
- SHL SI,1
- ADD SI,OFFSET Segment_Adr-StartIndex*2
- LODSW {AX := Segment_Adr[pa] = ^source address }
- {(for pa=BACKGNDPAGE id. to BACKGNADR)}
- PUSH BP
-
- MOV BP,AX
-
- MOV DX,AX
- MOV BX,0*LINESIZE {DX:BX = ^source data}
-
- MOV AX,YMAX {AX = row counter }
-
- oneLine3:
- MOV SI,AX
- MOV DX,3CEh
- MOV AX,4105h {set write mode 1 }
- OUT DX,AX
- MOV AX,SI
-
- MOV SI,ES {first scroll old contents upwards: }
- MOV DS,SI {DS = ES = visible graphic page }
- MOV SI,1*LINESIZE {from graphic row 1}
- MOV DI,0*LINESIZE {to graphic row 0 }
- MOV CX,YMAX*LINESIZE {199 rows }
- REP MOVSB
-
- PUSH AX
- MOV DX,3CEh {select write mode 0}
- MOV AX,4005h
- OUT DX,AX
-
- MOV DX,3C4h
- MOV AX,0102h {select write plane 0 }
- OUT DX,AX
- MOV DS,BP {now make new row visible: }
- MOV SI,BX {DS:SI = ^row to move }
- MOV CX,LINESIZE / 2 {1 row }
- REP MOVSW
-
- SHL AH,1 {select write plane 1 }
- OUT DX,AX
- ADD SI,PAGESIZE-LINESIZE
- MOV CX,LINESIZE / 2 {1 row }
- SUB DI,LINESIZE
- REP MOVSW
-
- SHL AH,1 {select write plane 2 }
- OUT DX,AX
- ADD SI,PAGESIZE-LINESIZE
- MOV CX,LINESIZE / 2 {1 row }
- SUB DI,LINESIZE
- REP MOVSW
-
- SHL AH,1 {select write plane 3 }
- OUT DX,AX
- ADD SI,PAGESIZE-LINESIZE
- MOV CX,LINESIZE / 2 {1 row }
- SUB DI,LINESIZE
- REP MOVSW
-
- MOV AH,$F {select all 4 planes }
- OUT DX,AX
-
- ADD BX,LINESIZE {increase source pointer }
- POP AX
-
- {--- insertion to realize timing:}
- MOV SI,BP {temporary BP }
- POP BP {TP's old BP }
- PUSH AX {save all registers needed later }
- PUSH BX
- PUSH SI
- PUSH ES
- MOV AX,SEG @DATA {restore TP's data segment }
- MOV DS,AX
- END;
- INC(counter);
- WHILE ClockTicks<t+counter*temp DO BEGIN END;
- ASM;
- POP ES
- POP SI
- POP BX
- POP AX
- PUSH BP
- MOV BP,SI
- {--- end of insertion}
-
- DEC AX {all rows done? }
- JNS oneLine3 {no, next row }
-
- MOV DX,3CEh {restore write mode 0 }
- MOV AX,4005h
- OUT DX,AX
-
- POP BP
- POP DS
- END;
- END;
- END;
- END;
-
- PROCEDURE ScrollHorizontal(pa,time:WORD; left:BOOLEAN);
- { in: pa = page, which contents will be made visible }
- { time = time (in millisceconds) for this action (approx.) }
- { left = TRUE/FALSE for: from left to right/vice versa }
- { 1-PAGE= (visible) graphic page on which to draw }
- {out: - }
- {rem: the contents of page "pa" has been copied to page 1-PAGE }
- LABEL oneColumn1,oneColumn2,oneColumn3,oneColumn4;
- CONST n=Pred(LINESIZE); {number of executions of the delay loop }
- VAR counter:WORD;
- ClockTicks:LONGINT ABSOLUTE $40:$6C;
- t:LONGINT;
- temp:REAL;
- BEGIN
- t:=ClockTicks;
- counter:=0;
- temp:=0.0182*time/n;
- IF pa<>BACKGNDPAGE
- THEN BEGIN
- IF left
- THEN BEGIN {scroll to the left }
- ASM
- MOV DX,3C4h
- MOV AX,0F02h {access all 4 planes at once }
- OUT DX,AX
- MOV DX,3CEh
- MOV AX,4105h {set write mode 1 }
- OUT DX,AX
-
- MOV SI,1
- SUB SI,PAGE
- AND SI,1
- SHL SI,1
- ADD SI,OFFSET Segment_Adr-StartIndex*2
- LODSW
- MOV ES,AX {ES := Segment_Adr[1 - PAGE] = ^visible page }
-
- MOV SI,pa
- AND SI,3
- SHL SI,1
- ADD SI,OFFSET Segment_Adr-StartIndex*2
- LODSW {AX := Segment_Adr[pa] = ^source address}
-
- PUSH DS
- MOV DX,AX
- MOV BX,0*LINESIZE+0 {DX:BX = ^source data}
-
- MOV AX,LINESIZE-1 {AX = column counter}
-
- oneColumn2: {scroll old screen contents to the right:}
- MOV SI,ES
- MOV DS,SI {DS = ES = visible graphic page }
- MOV SI,PAGESIZE-2
- MOV DI,PAGESIZE-1
- MOV CX,PAGESIZE-1
- STD
- REP MOVSB
- CLD
-
- MOV CX,SEG @DATA
- MOV DS,CX {DS = ^TP's data}
- MOV CX,YMAX+1 {CX = row counter }
-
- MOV SI,AX
- XOR DI,DI
- MOV BX,LINESIZE-1
- MOV DS,DX {DS = ^source data}
-
- @oneRow: {update first column: }
- MOVSB
- ADD SI,BX {position at next row: }
- ADD DI,BX {works, because BX + 1 = LINESIZE}
- LOOP @oneRow
-
- {--- insertion to realize timing:}
- PUSH AX {save all registers needed later }
- PUSH DX
- PUSH ES
- MOV AX,SEG @DATA {restore TP's data segment }
- MOV DS,AX
- END;
- INC(counter);
- WHILE ClockTicks<t+counter*temp DO BEGIN END;
- ASM;
- POP ES
- POP DX
- POP AX
- {--- end of insertion}
-
- DEC AX {all columns done? }
- JNS oneColumn2 {no, next column }
-
- MOV DX,3CEh {restore write mode 0 }
- MOV AX,4005h
- OUT DX,AX
- POP DS
- END;
- END
- ELSE BEGIN {scroll to the right }
- ASM
- MOV DX,3C4h
- MOV AX,0F02h {access all 4 planes at once }
- OUT DX,AX
- MOV DX,3CEh
- MOV AX,4105h {set write mode 1 }
- OUT DX,AX
-
- MOV SI,1
- SUB SI,PAGE
- AND SI,1
- SHL SI,1
- ADD SI,OFFSET Segment_Adr-StartIndex*2
- LODSW
- MOV ES,AX {ES := Segment_Adr[1 - PAGE] = ^visible page }
-
- MOV SI,pa
- AND SI,3
- SHL SI,1
- ADD SI,OFFSET Segment_Adr-StartIndex*2
- LODSW {AX := Segment_Adr[pa] = ^source address}
-
- PUSH DS
- MOV DX,AX
- MOV BX,0*LINESIZE+0 {DX:BX = ^source data}
-
- MOV AX,0 {AX = column counter}
-
- oneColumn1: {scroll old screen contents to the left:}
- MOV SI,ES
- MOV DS,SI {DS = ES = visible graphic page }
- MOV SI,1
- XOR DI,DI
- MOV CX,PAGESIZE-1
- REP MOVSB
-
- MOV CX,SEG @DATA
- MOV DS,CX {DS = ^TP's data}
- MOV CX,YMAX+1 {CX = row counter }
-
- MOV SI,AX
- MOV DI,LINESIZE-1
- MOV BX,LINESIZE-1
- MOV DS,DX {DS = ^source data}
-
- @oneRow: {update last column: }
- MOVSB
- ADD SI,BX {position at next row: }
- ADD DI,BX {works, because BX + 1 = LINESIZE}
- LOOP @oneRow
-
- {--- insertion to realize timing:}
- PUSH AX {save all registers needed later }
- PUSH DX
- PUSH ES
- MOV AX,SEG @DATA {restore TP's data segment }
- MOV DS,AX
- END;
- INC(counter);
- WHILE ClockTicks<t+counter*temp DO BEGIN END;
- ASM;
- POP ES
- POP DX
- POP AX
- {--- end of insertion}
-
- INC AX {all columns done? }
- CMP AX,LINESIZE
- JB oneColumn1 {no, next column }
-
- MOV DX,3CEh {restore write mode 0 }
- MOV AX,4005h
- OUT DX,AX
- POP DS
- END;
- END;
- END
- ELSE BEGIN {pa = BACKGNDPAGE, thus copy from RAM to VRAM}
- IF EMSused
- THEN EMSFillFrame(BackgroundEMSHandle); {prepare EMS access }
- IF left
- THEN BEGIN {scroll to the left }
- ASM
- MOV SI,1
- SUB SI,PAGE
- AND SI,1
- SHL SI,1
- ADD SI,OFFSET Segment_Adr-StartIndex*2
- LODSW
- MOV ES,AX {ES := Segment_Adr[1 - PAGE] = ^visible page }
-
- MOV SI,pa
- AND SI,3
- SHL SI,1
- ADD SI,OFFSET Segment_Adr-StartIndex*2
- LODSW {AX := Segment_Adr[pa] = ^source address}
-
- PUSH DS
- MOV DX,AX
- MOV BX,0*LINESIZE+0 {DX:BX = ^source data}
- MOV AX,LINESIZE-1 {column counter}
-
- oneColumn4: {scroll old screen contents to the right:}
- MOV SI,DX
- MOV DI,AX
- MOV DX,3C4h
- MOV AX,0F02h {access all 4 planes at once }
- OUT DX,AX
- MOV DX,3CEh
- MOV AX,4105h {set write mode 1 }
- OUT DX,AX
- MOV DX,SI
- MOV AX,DI
-
- MOV SI,ES
- MOV DS,SI {DS = ES = visible graphic page }
- MOV SI,PAGESIZE-2
- MOV DI,PAGESIZE-1
- MOV CX,PAGESIZE-1
- STD
- REP MOVSB
- CLD
-
- MOV CX,SEG @DATA
- MOV DS,CX {DS = ^TP's data}
- MOV CX,YMAX+1 {CX = row counter }
-
- MOV SI,AX {column counter}
- XOR DI,DI
- MOV BX,LINESIZE-1
- MOV DS,DX {DS = ^source data}
-
- PUSH AX
- PUSH DX
- MOV DX,3CEh {select write mode 0}
- MOV AX,4005h
- OUT DX,AX
-
- MOV DX,3C4h
-
- @oneRow0: {update first column: }
- MOV AX,0802h {select write plane 3 }
- OUT DX,AX
- MOV AL,[SI +3*PAGESIZE]
- MOV ES:[DI],AL
- MOV AX,0402h {select write plane 2 }
- OUT DX,AX
- MOV AL,[SI +2*PAGESIZE]
- MOV ES:[DI],AL
- MOV AX,0202h {select write plane 1 }
- OUT DX,AX
- MOV AL,[SI +1*PAGESIZE]
- MOV ES:[DI],AL
- MOV AX,0102h {select write plane 0 }
- OUT DX,AX
- MOVSB
- ADD SI,BX {position at next row: }
- ADD DI,BX {works, because BX + 1 = LINESIZE}
- LOOP @oneRow0
-
-
- {--- insertion to realize timing:}
- PUSH ES {save all registers needed later }
- MOV AX,SEG @DATA {restore TP's data segment }
- MOV DS,AX
- END;
- INC(counter);
- WHILE ClockTicks<t+counter*temp DO BEGIN END;
- ASM;
- POP ES
- {--- end of insertion}
-
- POP DX
- POP AX
- DEC AX {all columns done? }
- JNS oneColumn4 {no, next column }
-
- MOV DX,3CEh {restore write mode 0 }
- MOV AX,4005h
- OUT DX,AX
- POP DS
- END;
- END
- ELSE BEGIN {scroll to the right }
- ASM
- MOV SI,1
- SUB SI,PAGE
- AND SI,1
- SHL SI,1
- ADD SI,OFFSET Segment_Adr-StartIndex*2
- LODSW
- MOV ES,AX {ES := Segment_Adr[1 - PAGE] = ^visible page }
-
- MOV SI,pa
- AND SI,3
- SHL SI,1
- ADD SI,OFFSET Segment_Adr-StartIndex*2
- LODSW {AX := Segment_Adr[pa] = ^source address}
-
- PUSH DS
- MOV DX,AX
- MOV BX,0*LINESIZE+0 {DX:BX = ^source data}
-
- MOV AX,0 {AX = column counter}
-
- oneColumn3: {scroll old screen contents to the left:}
- MOV SI,DX
- MOV DI,AX
- MOV DX,3C4h
- MOV AX,0F02h {access all 4 planes at once }
- OUT DX,AX
- MOV DX,3CEh
- MOV AX,4105h {set write mode 1 }
- OUT DX,AX
- MOV DX,SI
- MOV AX,DI
-
- MOV SI,ES
- MOV DS,SI {DS = ES = visible graphic page }
- MOV SI,1
- XOR DI,DI
- MOV CX,PAGESIZE-1
- REP MOVSB
-
- MOV CX,SEG @DATA
- MOV DS,CX {DS = ^TP's data}
- MOV CX,YMAX+1 {CX = row counter }
-
- MOV SI,AX
- MOV DI,LINESIZE-1
- MOV BX,LINESIZE-1
- MOV DS,DX {DS = ^source data}
-
- PUSH AX
- PUSH DX
- MOV DX,3CEh {select write mode 0}
- MOV AX,4005h
- OUT DX,AX
-
- MOV DX,3C4h
-
- @oneRow: {update last column: }
- MOV AX,0802h {select write plane 3 }
- OUT DX,AX
- MOV AL,[SI +3*PAGESIZE]
- MOV ES:[DI],AL
- MOV AX,0402h {select write plane 2 }
- OUT DX,AX
- MOV AL,[SI +2*PAGESIZE]
- MOV ES:[DI],AL
- MOV AX,0202h {select write plane 1 }
- OUT DX,AX
- MOV AL,[SI +1*PAGESIZE]
- MOV ES:[DI],AL
- MOV AX,0102h {select write plane 0 }
- OUT DX,AX
- MOVSB
- ADD SI,BX {position at next row: }
- ADD DI,BX {works, because BX + 1 = LINESIZE}
- LOOP @oneRow
-
- {--- insertion to realize timing:}
- PUSH ES {save all registers needed later }
- MOV AX,SEG @DATA {restore TP's data segment }
- MOV DS,AX
- END;
- INC(counter);
- WHILE ClockTicks<t+counter*temp DO BEGIN END;
- ASM;
- POP ES
- {--- end of insertion}
-
- POP DX
- POP AX
-
- INC AX {all columns done? }
- CMP AX,LINESIZE
- JB oneColumn3 {no, next column }
-
- MOV DX,3CEh {restore write mode 0 }
- MOV AX,4005h
- OUT DX,AX
- POP DS
- END;
- END;
- END
- END;
-
- PROCEDURE CircleIn(pa,time:WORD);
- { in: pa = page, which contents will be made visible }
- { time = time (in millisceconds) for this action (approx.) }
- {out: - }
- {rem: the contents of page "pa" has been copied to page 1-PAGE }
- CONST centerX=XMAX DIV 2; {middle of screen}
- centerY=YMAX DIV 2;
- k=189; {number of circles := sqrt(centerX² + centerY²), rounded up}
- adjust=0.707106781; {compensation in diagonal direction = 1/sqrt(2) }
- n=TRUNC(k/adjust); {number of executions of the delay loop }
- VAR radqu,x,y,x0,y0,u1,u2,u3,u4,v1,v2,v3,v4:WORD;
- counter:WORD;
- ClockTicks:LONGINT ABSOLUTE $40:$6C;
- t:LONGINT;
- radius,temp:REAL;
- BEGIN
- t:=ClockTicks;
- counter:=0;
- temp:=0.0182*time/n;
- x0:=centerX + StartVirtualX;
- y0:=centerY + StartVirtualY;
- {unfortunately, FOR true_radius:=1 TO k STEP 1/adjust isn't possible in TP}
- radius:=0.0;
- REPEAT
- radqu:=TRUNC(sqr(radius));
- FOR x:=0 TO TRUNC(radius/sqrt(2)) DO {compute octant }
- BEGIN
- y:=TRUNC(sqrt(radqu-sqr(x))); {Pythagorean proposition}
- u1:=x0-x; v1:=y0-y; {use axial- and point symmetrie }
- u2:=x0+x; v2:=y0+y;
- u3:=x0-y; v3:=y0-x;
- u4:=x0+y; v4:=y0+x;
- PutPixel(u1,v1,PageGetPixel(u1,v1,pa));
- PutPixel(u1,v2,PageGetPixel(u1,v2,pa));
- PutPixel(u2,v1,PageGetPixel(u2,v1,pa));
- PutPixel(u2,v2,PageGetPixel(u2,v2,pa));
- PutPixel(u3,v3,PageGetPixel(u3,v3,pa));
- PutPixel(u3,v4,PageGetPixel(u3,v4,pa));
- PutPixel(u4,v3,PageGetPixel(u4,v3,pa));
- PutPixel(u4,v4,PageGetPixel(u4,v4,pa));
- END;
- radius:=radius+adjust;
- INC(counter);
- WHILE ClockTicks<t+counter*temp DO BEGIN END;
- UNTIL radius>=k;
- END;
-
- BEGIN {of FadeIn}
- IF (pa<0) OR (pa>SCROLLPAGE)
- THEN Error:=Err_InvalidPageNumber
- ELSE CASE style OF
- Fade_Squares :WipeIn(pa,ti);
- Fade_Moiree1..Fade_Moiree14:Chaos(pa,ti,style+1-Fade_Moiree1);
- Fade_SweepInFromTop: SweepVertical(pa,ti,TRUE);
- Fade_SweepInFromBottom: SweepVertical(pa,ti,FALSE);
- Fade_SweepInFromLeft: SweepHorizontal(pa,ti,TRUE);
- Fade_SweepInFromRight: SweepHorizontal(pa,ti,FALSE);
- Fade_ScrollInFromTop: ScrollVertical(pa,ti,TRUE);
- Fade_ScrollInFromBottom:ScrollVertical(pa,ti,FALSE);
- Fade_ScrollInFromLeft: ScrollHorizontal(pa,ti,TRUE);
- Fade_ScrollInFromRight: ScrollHorizontal(pa,ti,FALSE);
- Fade_Circles : CircleIn(pa,ti);
- Fade_Moiree15:Chaos2(pa,ti,style+1-Fade_Moiree15);
- else Error:=Err_InvalidFade
- END;
- END;
-
-
- PROCEDURE IntroScroll(n,wait:WORD);
- { in: n = number of lines to be scrolled up }
- { wait = time (in ms) the program will wait after each line }
- {rem: scrolling always starts at page 0 (=$A000:0000) }
- { After the scrolling, the command "Screen(1-page)" must be issued!}
- BEGIN
- Screen(0); {position at $A000:0000 }
- ASM
- XOR SI,SI {compute address of page 0 = $A000:0000 }
- AND SI,3 {page value *2 (word-sized entries!)}
- SHL SI,1 {add start address of array to that }
- ADD SI,OFFSET Offset_Adr-StartIndex*2 {evtl. correct displacement }
- LODSW {and fetch value}
- MOV BX,AX
- MOV CX,n
- MOV SI,wait
-
- @oneline:
- ADD BX,LINESIZE
-
- CLI {May not be interrupted! }
- MOV DX,StatusReg
- @WaitNotHSyncLoop:
- in al,dx
- and al,1
- jz @WaitNotHSyncLoop
- @WaitHSyncLoop:
- in al,dx
- and al,1
- jz @WaitHSyncLoop
-
- MOV DX,CRTAddress {CRT-Controller}
- MOV AL,$0D {LB-startaddress-register}
- OUT DX,AL
- INC DX
-
- MOV AL,BL
- OUT DX,AL {set LB of new starting address }
- DEC DX
- MOV AL,$0C
- OUT DX,AL
- INC DX
- MOV AL,BH {set HB of new starting address }
- OUT DX,AL
- STI
-
- PUSH BX
- PUSH CX
- PUSH SI
- PUSH SI
- CALL CRT.Delay
- POP SI
- POP CX
- POP BX
- LOOP @oneline
-
- END;
- END;
-
- PROCEDURE CopyVRAMtoVRAM(source,dest:POINTER; len:WORD); ASSEMBLER;
- { in: source = starting address}
- { dest = destination address }
- { len = length of the area to copy }
- {out: - }
- {rem: The both areas may not overlap each other }
- { WriteMode1 will be used; therefore, the length "len" counts }
- { for 4 bytes each: for example, a call like }
- { CopyVRAMtoVRAM(Ptr($A000,0),Ptr($A000,PAGESIZE),PAGESIZE) }
- { would copy a complete page (4*PAGESIZE = 64000 bytes)}
- ASM
- MOV AX,4105h {enable write mode 1 }
- MOV DX,3CEh
- OUT DX,AX
- MOV AX,0F02h {access all 4 planes at once }
- MOV DX,3C4h
- OUT DX,AX
-
- MOV BX,DS
-
- LES DI,dest
- LDS SI,source
- MOV CX,len
- CLD
- REP MOVSB
-
- MOV DS,BX
-
- MOV AX,4005h
- MOV DX,3CEh
- OUT DX,AX
- END;
-
-
- PROCEDURE InitRoutines;
- { in: USEEMS = TRUE for: use EMS-memory for BACKGNDPAGE contents}
- {out: SpriteN[],SPRITEAD[],SPRITEPTR[],SPRITESIZE[],BackTile[] have been }
- { initialised to "completely empty"}
- { NextSprite[] has been set so that each sprite is its own }
- { successor }
- { PAGE, PAGEADR have been set to graphic page 0 }
- { BACKGNDADR has been set to the background page }
- { SCROLLADR has been set to the scrollable background page }
- { BACKGROUNDMODE has been set to STATIC }
- { The default tile for the scolling background has been set to #0 }
- { StartVirtualX,StartVirtualY =0 (that is: virtual = absolute coord.)}
- { oldMode = old graphicmode }
- { Error has been set, if no VGA-card could be found in the system }
- { CycleTime = 0, that is: no min. time for animation cycle }
- { Color = 15, that is: white }
- { CurrentFont = pointer to internal font}
- { FontHeight, FontWidth = sizes of internal font }
- { FontType = its type }
- { ActualColors = default color palette of mode $13 }
- { CRTAddress = port address of CRT-address register}
- { StatusReg = port address of state register }
- { EMSused = TRUE, if EMS-memory has been allocated for BACKGNDPAGE }
- { BackgroundEMSHandle = handle to allocated EMS-block (if EMSused=TRUE) }
- { buf = pointer to allocated heap-block (if EMSused=FALSE) }
- { Win* coordinates have been set to the complete animation window }
- { SplitIndex has been set so that all sprites will be clipped to }
- { the animation window }
- {rem: This procedure should be called only once - namely in the very }
- { beginning - for initializing the whole package properly }
- TYPE rec=RECORD lw,hw:WORD END;
- VAR i,adj:WORD;
-
- FUNCTION IsVGA:BOOLEAN;
- BEGIN
- WITH Regs DO
- BEGIN
- AX:=$1A00;
- Intr($10,Regs);
- IsVGA:=(AL=$1A) AND {VGA's identify-adapter-function supported?}
- ( (BL=7) OR (BL=8) ) {monochrome or color VGA - adapter}
- END;
- END;
-
- BEGIN
- IF IsVGA THEN Error:=Err_None
- ELSE BEGIN
- Error:=Err_NoVGA;
- exit
- END;
-
- SetCycleTime(0);
-
- FillChar(SpriteN,SizeOf(SpriteN),0);
- FillChar(SPRITEAD,SizeOf(SPRITEAD),0);
- FillChar(SPRITESIZE,SizeOf(SPRITESIZE),0);
- FillChar(BackTile,SizeOf(BackTile),0);
-
- FOR i:=0 TO LoadMAX DO
- BEGIN
- NextSprite[i]:=i;
- SPRITEPTR[i]:=NIL
- END;
-
- BACKGNDADR:=Segment_Adr[BACKGNDPAGE]; {segment address of background page }
-
- PAGE:=0; {page to be drawn upon }
- PAGEADR:=Segment_Adr[PAGE];
- SCROLLADR:=Segment_Adr[SCROLLPAGE];
- SetBackgroundMode(STATIC);
- SetOffscreenTile(0);
-
- StartVirtualX:=0; StartVirtualY:=0; {virtual = absolute coordinates }
- Color:=white; {set actual drawing color to white }
- regs.ah:=$f; intr($10,regs); oldMode:=regs.al;
-
- ActualColors:=DefaultColors;
- {SetShadowTab(Schatten) isn't needed, as the default values are set already}
-
- ASM {see if we are using color-/monochorme display}
- MOV DX,3CCh {use output register: }
- IN AL,DX
- TEST AL,1 {is it a color display? }
- MOV DX,3D4h
- JNZ @L1 {yes }
- MOV DX,3B4h {no }
- @L1: {DX = 3B4h / 3D4h = CRTAddress-register for monochrome/color}
- MOV CRTAddress,DX
- ADD DX,6 {DX = 3BAh / 3DAh = state register for monochrome/color}
- MOV StatusReg,DX
- END; {of ASM}
-
- LoadFont(''); {load internal font }
- SetAnimateWindow(0,0,319,199);
-
- EMSused:=FALSE;
-
- IF EmsInstalled(BACKGNDADR) AND
- EMSIsHardWareEMS AND
- (EMSPagesAvailable>=4) AND
- (EMSError=0)
- THEN BEGIN {use EMS }
- BackgroundEMSHandle:=EMSAllocate(4); {allocate 64K }
- If EmsError<>0
- THEN BEGIN {don't do it}
- WriteLn ('EMS-Allozierungsfehler!' );
- EMSRelease(BackgroundEMSHandle);
- END
- ELSE BEGIN
- EMSused:=TRUE;
- buf:=Ptr(BACKGNDADR,0)
- END;
- END;
-
- IF NOT EMSused
- THEN BEGIN {no, not enough or "wrong" EMS-memory, use heap instead: }
- New(buf)
- END
- ELSE EMSFillFrame(BackgroundEMSHandle); {prepare EMS access }
-
- FillChar(buf^,SizeOf(buf^),0);
- adj:=rec(buf).lw DIV 16;
- IF (rec(buf).lw MOD 16)<>0
- THEN inc(adj); {round towards increasing addresses }
- inc(rec(buf).hw,adj);
- rec(buf).lw:=0;
-
- IF rec(buf).lw<>0
- THEN BEGIN
- WRITELN('Fehler: buf^ liegt nicht auf Segmentgrenze');
- Halt
- END
- ELSE BEGIN
- Segment_Adr[BACKGNDPAGE]:=rec(buf).hw;
- Offset_Adr[BACKGNDPAGE]:=0;
- BACKGNDADR:=rec(buf).hw
- END;
- SetAnimateWindow(0,0,XMAX,YMAX);
- SetSplitIndex(-1); {=clip all }
- END;
-
- PROCEDURE CloseRoutines;
- { in: oldMode = old graphicmode, to which we'll switch back }
- { EMSused = did we use EMS memory for BACKGNDPAGE? }
- { BackgroundEMSHandle = if yes, then this is the handle to it }
- { buf = if no, then this is the pointer to the normal heap area}
- {out: - }
- BEGIN
- regs.al:=oldMode; regs.ah:=0; intr($10,regs);
- IF EMSused
- THEN EMSRelease(BackgroundEMSHandle)
- ELSE Release(buf);
- END;
-
- FUNCTION GetErrorMessage:STRING;
- { in: Error = number of the occurred error }
- {out: the error described in words}
- BEGIN
- CASE Error OF
- Err_None:GetErrorMessage:='No Error';
- Err_NotEnoughMemory:GetErrorMessage:='Not enough memory available on heap';
- Err_FileIO:GetErrorMessage:='I/O-error with file';
- Err_InvalidSpriteNumber:GetErrorMessage:='Invalid sprite number used';
- Err_NoSprite:GetErrorMessage:='No (or corrupted) sprite file';
- Err_InvalidPageNumber:GetErrorMessage:='Invalid page number used';
- Err_NoVGA:GetErrorMessage:='No VGA-card found';
- Err_NoPicture:GetErrorMessage:='No (or corrupted) picture file';
- Err_InvalidPercentage:GetErrorMessage:='Percentage value must be 0..100';
- Err_NoTile:GetErrorMessage:='No (or corrupted) tile/sprite file';
- Err_InvalidTileNumber:GetErrorMessage:='Invalid tile number used';
- Err_InvalidCoordinates:GetErrorMessage:='Invalid coordinates used';
- Err_BackgroundToBig:GetErrorMessage:='Background to big for tile-buffer';
- Err_InvalidMode:GetErrorMessage:='Only STATIC or SCROLLING allowed here';
- Err_InvalidSpriteLoadNumber:GetErrorMessage:='Invalid spriteload number used';
- Err_NoPalette:GetErrorMessage:='No (or corrupted) palette file';
- Err_PaletteWontFit:GetErrorMessage:='Attempt to write beyond palette end';
- Err_InvalidFade:GetErrorMessage:='Invalid fade style used';
- Err_NoFont:GetErrorMessage:='No (or corrupted) font file';
- Err_EMSError:GetErrorMessage:='Problems with EMS memory';
- ELSE GetErrorMessage:='Unknown error';
- END;
- END;
-
- FUNCTION FindFile(P:PathStr):PathStr;
- { in: P = file to search, incl. starting path}
- {out: complete pathname to file }
- {rem: If the file is not found in the specified directory, then all }
- { subdirectories will be searched through recursively.}
- { If the search still doesn't find the file, '' will be returned }
- VAR D: DirStr;
- N: NameStr;
- E: ExtStr;
- DateiName:STRING[12];
- temp:PathStr;
-
- FUNCTION SearchFile(Pfad:PathStr):PathStr;
- { in: DateiName = file to be searched}
- { Pfad = path to start the search from }
- {out: complete pathname to file or '', if the file is not found }
- VAR Datei,Dir:SearchRec;
- BEGIN
- FindFirst(Pfad+DateiName,AnyFile,Datei);
- WHILE DosError=0 DO
- BEGIN
- IF (Datei.Attr AND Directory)<>Directory
- THEN BEGIN
- SearchFile:=Pfad+Datei.Name;
- Exit
- END;
- FindNext(Datei)
- END;
-
- {here: file has not be found in current directory }
- FindFirst(Pfad+'*.*',Directory,Dir);
- WHILE DosError=0 DO
- BEGIN
- IF ((Dir.Attr AND Directory)=Directory) AND (Dir.Name[1]<>'.')
- THEN BEGIN {search through next directory}
- temp:=SearchFile(Pfad+Dir.Name+'\');
- IF temp<>''
- THEN BEGIN {found recursively!}
- SearchFile:=temp;
- Exit
- END;
- END;
- FindNext(Dir);
- END;
- SearchFile:='';
- END;
-
- BEGIN
- FSplit(P,D,N,E);
- DateiName:=N+E;
- FindFile:=SearchFile(D)
- END;
-
-
-
- BEGIN
-
- InitRoutines;
-
- END.
-